cfaf6cb7e2fbc90f7e5558698f19fc92f8920cb3
[lcr.git] / apppbx.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** The EndpointAppPBX implements PBX4Linux                                   **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12
13 #include "main.h"
14
15 class EndpointAppPBX *apppbx_first = NULL;
16
17 int action_timeout(struct lcr_timer *timer, void *instance, int index);
18 int match_timeout(struct lcr_timer *timer, void *instance, int index);
19 int redial_timeout(struct lcr_timer *timer, void *instance, int index);
20 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index);
21 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index);
22 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index);
23 int password_timeout(struct lcr_timer *timer, void *instance, int index);
24 int callback_timeout(struct lcr_timer *timer, void *instance, int index);
25
26 /*
27  * EndpointAppPBX constructor
28  */
29 EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin)
30 {
31         class EndpointAppPBX **apppointer;
32
33         memset(&e_crypt_handler, 0, sizeof(e_crypt_handler));
34         add_timer(&e_crypt_handler, crypt_handler, this, 0);
35         memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh));
36         add_timer(&e_vbox_refresh, vbox_refresh, this, 0);
37         memset(&e_action_timeout, 0, sizeof(e_action_timeout));
38         add_timer(&e_action_timeout, action_timeout, this, 0);
39         memset(&e_match_timeout, 0, sizeof(e_match_timeout));
40         add_timer(&e_match_timeout, match_timeout, this, 0);
41         memset(&e_redial_timeout, 0, sizeof(e_redial_timeout));
42         add_timer(&e_redial_timeout, redial_timeout, this, 0);
43         memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout));
44         add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0);
45         memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout));
46         add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0);
47         memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout));
48         add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0);
49         memset(&e_callback_timeout, 0, sizeof(e_callback_timeout));
50         add_timer(&e_callback_timeout, callback_timeout, this, 0);
51         memset(&e_password_timeout, 0, sizeof(e_password_timeout));
52         add_timer(&e_password_timeout, password_timeout, this, 0);
53         e_powerdial_on = 0;
54
55         /* add application to chain */
56         next = NULL;
57         apppointer = &apppbx_first;
58         while(*apppointer)
59                 apppointer = &((*apppointer)->next);
60         *apppointer = this;
61
62         /* initialize */
63         memset(&e_ext, 0, sizeof(struct extension));
64         // *************** NOTE: also change value in read_extension() **************
65         e_ext.rights = 4; /* international */
66         e_ext.rx_gain = e_ext.tx_gain = 0;
67         e_state = EPOINT_STATE_IDLE;
68         e_ext.number[0] = '\0';
69         e_extension_interface[0] = '\0';
70         memset(&e_callerinfo, 0, sizeof(struct caller_info));
71         memset(&e_dialinginfo, 0, sizeof(struct dialing_info));
72         memset(&e_connectinfo, 0, sizeof(struct connect_info));
73         memset(&e_redirinfo, 0, sizeof(struct redir_info));
74         memset(&e_capainfo, 0, sizeof(struct capa_info));
75         e_start = e_stop = 0;
76         e_origin = origin;
77         e_ruleset = ruleset_main;
78         if (e_ruleset)
79                 e_rule = e_ruleset->rule_first;
80         e_rule_nesting = 0;
81         e_action = NULL;
82         e_match_to_action = NULL;
83         e_select = 0;
84         e_extdialing = e_dialinginfo.id;
85 //        e_knocking = 0;
86 //        e_knocktime = 0;
87         e_hold = 0;
88 //        e_join_tone[0] = e_hold_tone[0] = '\0';
89         e_join_pattern /*= e_hold_pattern*/ = 0;
90         e_tone[0] = '\0';
91         e_adminid = 0; // will be set, if call was initiated via admin socket
92         e_powerdelay = 0;
93         e_powerlimit = 0;
94         e_cbdialing[0] = '\0';
95         e_cbcaller[0] = '\0';
96         e_cbto[0] = '\0';
97         memset(&e_callbackinfo, 0, sizeof(struct caller_info));
98         e_connectedmode = 0;
99         e_dtmf = 0;
100         e_dtmf_time = 0;
101         e_dtmf_last = 0;
102         e_enablekeypad = 0;
103         e_multipoint_cause = 0;
104         e_multipoint_location = 0;
105         e_dialing_queue[0] = '\0';
106         e_crypt = CRYPT_OFF;
107         e_crypt_state = CM_ST_NULL;
108         e_crypt_keyengine_busy = 0;
109         e_crypt_info[0] = '\0'; 
110         e_overlap = 0;
111         e_vbox[0] = '\0';
112         e_tx_state = NOTIFY_STATE_ACTIVE;
113         e_rx_state = NOTIFY_STATE_ACTIVE;
114         e_join_cause = e_join_location = 0;
115 /*********************************
116  *********************************
117  ********* ATTENTION *************
118  *********************************
119  *********************************/
120 /* if you add new values, that must be initialized, also check if they must
121  * be initialized when doing callback
122  */
123
124 }
125
126 /*
127  * EpointAppPBX destructor
128  */
129 EndpointAppPBX::~EndpointAppPBX(void)
130 {
131         class EndpointAppPBX *temp, **tempp;
132
133         del_timer(&e_crypt_handler);
134         del_timer(&e_vbox_refresh);
135         del_timer(&e_action_timeout);
136         del_timer(&e_match_timeout);
137         del_timer(&e_redial_timeout);
138         del_timer(&e_powerdial_timeout);
139         del_timer(&e_cfnr_timeout);
140         del_timer(&e_cfnr_call_timeout);
141         del_timer(&e_callback_timeout);
142         del_timer(&e_password_timeout);
143
144         /* detach */
145         temp =apppbx_first;
146         tempp = &apppbx_first;
147         while(temp) {
148                 if (temp == this)
149                         break;
150
151                 tempp = &temp->next;
152                 temp = temp->next;
153         }
154         if (temp == 0)
155                 FATAL("Endpoint not in endpoint's list.\n");
156         *tempp = next;
157
158 }
159
160
161 /*
162  * trace header for application
163  */
164 void EndpointAppPBX::trace_header(const char *name, int direction)
165 {
166         struct trace _trace;
167
168         char msgtext[sizeof(_trace.name)];
169
170         SCPY(msgtext, name);
171
172         /* init trace with given values */
173         start_trace(-1,
174                     NULL,
175                     numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
176                     e_dialinginfo.id,
177                     direction,
178                     CATEGORY_EP,
179                     ea_endpoint->ep_serial,
180                     msgtext);
181 }
182
183
184 EPOINT_STATE_NAMES
185
186 /* set new endpoint state
187  */
188 void EndpointAppPBX::new_state(int state)
189 {
190 #if 0
191         if (e_state != state) {
192                 trace_header("NEW STATE", DIRECTION_NONE);
193                 add_trace("state", "old", "%s", state_name[e_state]);
194                 add_trace("state", "new", "%s", state_name[state]);
195                 end_trace();
196         }
197 #endif
198         e_state = state;
199 }
200
201
202 /* release join and port (as specified)
203  */
204 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force)
205 {
206         struct port_list *portlist;
207         struct lcr_msg *message;
208         char cause[16];
209
210         /* message to test call */
211         admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
212
213         /* if a release is pending */
214         if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
215                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
216                 if (ea_endpoint->ep_join_id) {
217                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
218                         message->param.disconnectinfo.cause = joincause;
219                         message->param.disconnectinfo.location = joinlocation;
220                         message_put(message);
221                         ea_endpoint->ep_join_id = 0;
222                 }
223                 e_join_pattern = 0;
224 #if 0
225                 if (release != RELEASE_PORT_JOINONLY) {
226                         if (e_hold_id)
227                                 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
228                         e_hold_id = 0;
229                 }
230 #endif
231         }
232         if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
233                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
234                 while((portlist = ea_endpoint->ep_portlist)) {
235                         if (portlist->port_id) {
236                                 SPRINT(cause, "cause_%02x", portcause);
237                                 set_tone(portlist, cause);
238                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
239                                 message->param.disconnectinfo.cause = portcause;
240                                 message->param.disconnectinfo.location = portlocation;
241                                 message->param.disconnectinfo.force = force; // set, if port should release imediately
242                                 message_put(message);
243                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
244                         }
245                         ea_endpoint->free_portlist(portlist);
246                 }
247
248                 /* if callback is enabled, call back with the given caller id */
249                 if (e_callback_timeout.active) {
250                         /* reset some stuff */
251                         new_state(EPOINT_STATE_IDLE);
252                         memset(&e_connectinfo, 0, sizeof(struct connect_info));
253                         memset(&e_redirinfo, 0, sizeof(struct redir_info));
254                         e_start = e_stop = 0;
255                         e_ruleset = ruleset_main;
256                         if (e_ruleset)
257                                 e_rule = e_ruleset->rule_first;
258                         e_action = NULL;
259                         unsched_timer(&e_action_timeout);
260                         unsched_timer(&e_match_timeout);
261                         unsched_timer(&e_cfnr_timeout);
262                         unsched_timer(&e_cfnr_call_timeout);
263                         e_match_to_action = NULL;
264                         //e_select = 0;
265                         e_extdialing = e_dialinginfo.id;
266                         e_connectedmode = 0;
267                         e_dtmf = 0;
268                         e_dtmf_time = 0;
269                         e_dtmf_last = 0;
270                         e_enablekeypad = 0;
271                         e_multipoint_cause = 0;
272                         e_multipoint_location = 0;
273                         e_dialing_queue[0] = '\0';
274                         e_crypt = 0;
275                         e_crypt_state = CM_ST_NULL;
276                         e_crypt_keyengine_busy = 0;
277                         e_crypt_info[0] = '\0'; 
278                         e_tone[0] = '\0';
279                         e_overlap = 0;
280                         e_vbox[0] = '\0';
281                         e_tx_state = NOTIFY_STATE_ACTIVE;
282                         e_rx_state = NOTIFY_STATE_ACTIVE;
283                         e_join_cause = e_join_location = 0;
284                         e_rule_nesting = 0;
285                         /* the caller info of the callback user */
286                         memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
287                         memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
288                         /* create dialing by callerinfo */
289                         if (e_ext.number[0] && e_extension_interface[0]) {
290                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
291                                 /* create callback to the current terminal */
292                                 SCPY(e_dialinginfo.id, e_ext.number);
293                                 SCPY(e_dialinginfo.interfaces, e_extension_interface);
294                                 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
295                                 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
296                         } else {
297                                 if (e_cbto[0]) {
298                                         SCPY(e_dialinginfo.id, e_cbto);
299                                 } else {
300                                         /* numberrize caller id and use it to dial to the callback */
301                                         SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
302                                 }
303                                 e_dialinginfo.itype = INFO_ITYPE_ISDN;
304                                 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
305                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
306                         }
307                         return;
308                 }
309
310                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
311                 if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */
312                         trigger_work(&ea_endpoint->ep_delete);
313                 return;
314         }
315 }
316
317
318 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
319 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
320 {
321         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");
322
323         /* caller id is not restricted, so we do nothing */
324         if (*present != INFO_PRESENT_RESTRICTED)
325                 return;
326
327         /* only extensions are restricted */
328         if (!ext->number[0])
329                 return;
330
331         /* if we enabled anonymouse ignore */
332         if (ext->anon_ignore)
333                 return;
334
335         /* else we remove the caller id */
336         if (id)
337                 id[0] = '\0';
338         if (ntype)
339                 *ntype = INFO_NTYPE_UNKNOWN;
340 //      if (screen)
341 //              *screen = INFO_SCREEN_USER;
342 // maybe we should not make voip address anonymous
343 //      if (voip)
344 //              voip[0] = '\0';
345 // maybe it's no fraud to present extension id
346 //      if (extension)
347 //              extension[0] = '\0';
348         if (name)
349                 name[0] = '\0';
350 }
351
352 /* used display message to display callerid as available */
353 char *EndpointAppPBX::apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name)
354 {
355         static char display[81];
356
357         display[0] = '\0';
358         const char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
359
360         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");
361
362         if (!id)
363                 id = "";
364         if (!extension)
365                 extension = "";
366         if (!name)
367                 name = "";
368
369         /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
370
371         /* internal extension's caller id */
372         if (extension[0] && e_ext.display_int) {
373                 if (!display[0])
374                         SCAT(display, extension);
375                 if (display[0])
376                         SCAT(display, " ");
377                 if (itype == INFO_ITYPE_VBOX)
378                         SCAT(display, "(vbox)");
379                 else
380                         SCAT(display, "(int)");
381         }
382
383         /* external caller id */
384         if (!extension[0] && e_ext.display_ext) {
385                 if (!display[0]) {
386                         if (!cid[0]) {
387                                 if (present == INFO_PRESENT_RESTRICTED)
388                                         SCAT(display, "anonymous");
389                                 else
390                                         SCAT(display, "unknown");
391                         }
392                         else
393                                 SCAT(display, cid);
394                 }
395         }
396
397         /* display if callerid is anonymouse but available due anon-ignore */
398         if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED) {
399                 if (!cid[0])
400                         SCAT(display, "unknown");
401                 else 
402                         SCAT(display, cid);
403                 SCAT(display, " anon");
404         }
405
406         /* display if callerid is anonymouse but available due anon-ignore */
407         if (e_ext.display_fake && screen==INFO_SCREEN_USER && ntype!=INFO_NTYPE_NOTPRESENT) {
408                 if (!display[0]) {
409                         if (!id[0]) {
410                                 if (present == INFO_PRESENT_RESTRICTED)
411                                         SCAT(display, "anonymous");
412                                 else
413                                         SCAT(display, "unknown");
414                         }
415                         else
416                                 SCAT(display, cid);
417                 }
418                 SCAT(display, " fake");
419         }
420
421         /* caller name */
422         if (name[0] && e_ext.display_name) {
423                 if (!display[0] && cid[0])
424                                 SCAT(display, cid);
425                 if (display[0])
426                                 SCAT(display, " ");
427                 SCAT(display, name);
428         }
429
430         return(display);
431 }
432
433 /*
434  * uses the current state to notify activity
435  */
436 void EndpointAppPBX::notify_active(void)
437 {
438         struct port_list *portlist = ea_endpoint->ep_portlist;
439         struct lcr_msg *message;
440         int notify = 0;
441
442         switch(e_tx_state) {
443                 case NOTIFY_STATE_ACTIVE:
444                 /* we are already active, so we don't do anything */
445                 break;
446
447                 case NOTIFY_STATE_SUSPEND:
448                 notify = INFO_NOTIFY_USER_RESUMED;
449                 while(portlist) {
450                         set_tone(portlist, NULL);
451                         portlist = portlist->next;
452                 }
453                 portlist = ea_endpoint->ep_portlist;
454                 break;
455
456                 case NOTIFY_STATE_HOLD:
457                 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
458                 while(portlist) {
459                         set_tone(portlist, NULL);
460                         portlist = portlist->next;
461                 }
462                 portlist = ea_endpoint->ep_portlist;
463                 break;
464
465                 case NOTIFY_STATE_CONFERENCE:
466                 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
467                 while(portlist) {
468                         set_tone(portlist, NULL);
469                         portlist = portlist->next;
470                 }
471                 portlist = ea_endpoint->ep_portlist;
472                 break;
473
474                 default:
475                 PERROR("unknown e_tx_state = %d\n", e_tx_state);
476         }
477
478         if (notify)
479         while(portlist) {
480                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
481                 message->param.notifyinfo.notify = notify;
482                 message_put(message);
483                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
484                 portlist = portlist->next;
485         }
486 }
487
488
489 /*
490  * keypad functions during call. one example to use this is to put a call on hold or start a conference
491  */
492 void EndpointAppPBX::keypad_function(char digit)
493 {
494
495         /* we must be in a call, in order to send messages to the call */
496         if (e_ext.number[0] == '\0') {
497                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
498                 return;
499         }
500
501         switch(digit) {
502                 /* join conference */
503                 case '3':
504                 if (ea_endpoint->ep_join_id == 0) {
505                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
506                         break;
507                 }
508                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
509                 join_join();
510                 break;
511
512                 /* crypt shared */
513                 case '7':
514                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
515                 encrypt_shared();
516                 break;
517
518                 /* crypt key-exchange */
519                 case '8':
520                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
521                 encrypt_keyex();
522                 break;
523
524                 /* crypt off */
525                 case '9':
526                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
527                 encrypt_off();
528                 break;
529
530                 default:        
531                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
532         }
533 }
534
535
536 /* set tone pattern for port */
537 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
538 {
539         struct lcr_msg *message;
540
541         if (!tone)
542                 tone = "";
543
544         /* store for suspended processes */
545         SCPY(e_tone, tone);
546
547
548         if (e_join_pattern /* pattern are provided */
549          && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
550          && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
551          && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
552          && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
553          && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
554          && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
555          && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
556          && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
557          && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
558          && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
559          && tone[0] && !!strncmp(tone,"crypt_*",6)) {
560                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
561                 tone = "";
562         }
563
564         if (portlist) {
565                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
566                 SCPY(message->param.tone.dir, e_ext.tones_dir);
567                 SCPY(message->param.tone.name, tone);
568                 message_put(message);
569                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
570         } else {
571                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
572                 return;
573         }
574 }
575
576
577 /*
578  * hunts an mISDNport that is available for an outgoing call
579  * if no ifname was given, any interface that is not an extension
580  * will be searched.
581  */
582 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
583 {
584         struct interface *interface;
585         struct interface_port *ifport, *ifport_start;
586         struct select_channel *selchannel; 
587         struct mISDNport *mISDNport;
588         int index, i;
589         int there_is_an_external = 0;
590
591         interface = interface_first;
592
593         /* first find the given interface or, if not given, one with no extension */
594         checknext:
595         if (!interface) {
596                 if (!there_is_an_external && !(ifname && ifname[0])) {
597                         trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
598                         add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
599                         end_trace();
600                 }
601                 return(NULL);
602         }
603
604         /* check for given interface */
605         if (ifname && ifname[0]) {
606                 if (!strcasecmp(interface->name, ifname)) {
607                         /* found explicit interface */
608                         trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
609                         add_trace("interface", NULL, "%s", ifname);
610                         end_trace();
611                         goto foundif;
612                 }
613
614         } else {
615                 if (interface->external) {
616                         there_is_an_external = 1;
617                         /* found non extension */
618                         trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
619                         add_trace("interface", NULL, "%s", interface->name);
620                         end_trace();
621                         goto foundif;
622                 }
623         }
624
625         interface = interface->next;
626         goto checknext;
627 foundif:
628
629         /* see if interface has ports */
630         if (!interface->ifport) {
631                 /* no ports */
632                 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
633                 add_trace("interface", NULL, "%s", interface->name);
634                 end_trace();
635                 interface = interface->next;
636                 goto checknext;
637         }
638
639         /* select port by algorithm */
640         ifport_start = interface->ifport;
641         index = 0;
642         if (interface->hunt == HUNT_ROUNDROBIN) {
643                 while(ifport_start->next && index<interface->hunt_next) {
644                         ifport_start = ifport_start->next;
645                         index++;
646                 }
647                 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
648                 add_trace("port", NULL, "%d", ifport_start->portnum);
649                 add_trace("position", NULL, "%d", index);
650                 end_trace();
651         }
652
653         /* loop ports */
654         ifport = ifport_start;
655         nextport:
656
657         /* see if port is available */
658         if (!ifport->mISDNport) {
659                 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
660                 add_trace("port", NULL, "%d", ifport->portnum);
661                 add_trace("position", NULL, "%d", index);
662                 end_trace();
663                 goto portbusy;
664         }
665         mISDNport = ifport->mISDNport;
666
667         /* see if port is administratively blocked */
668         if (ifport->block) {
669                 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
670                 add_trace("port", NULL, "%d", ifport->portnum);
671                 add_trace("position", NULL, "%d", index);
672                 end_trace();
673                 goto portbusy;
674         }
675
676         /* see if link is up on PTP*/
677         if (mISDNport->l2hold && mISDNport->l2link<1) {
678                 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
679                 add_trace("port", NULL, "%d", ifport->portnum);
680                 add_trace("position", NULL, "%d", index);
681                 end_trace();
682                 goto portbusy;
683         }
684
685         /* check for channel form selection list */
686         *channel = 0;
687 #ifdef WITH_SS5
688         if (mISDNport->ss5) {
689                 class Pss5 *port;
690                 port = ss5_hunt_line(mISDNport);
691                 if (port) {
692                         *channel = port->p_m_b_channel;
693                         trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
694                         add_trace("port", NULL, "%d", ifport->portnum);
695                         add_trace("position", NULL, "%d", index);
696                         add_trace("channel", NULL, "%d", *channel);
697                         end_trace();
698                 }
699         } else
700 #endif
701         {
702                 selchannel = ifport->out_channel;
703                 while(selchannel) {
704                         switch(selchannel->channel) {
705                                 case CHANNEL_FREE: /* free channel */
706                                 if (mISDNport->b_reserved >= mISDNport->b_num)
707                                         break; /* all channel in use or reserverd */
708                                 /* find channel */
709                                 i = 0;
710                                 while(i < mISDNport->b_num) {
711                                         if (mISDNport->b_port[i] == NULL) {
712                                                 *channel = i+1+(i>=15);
713                                                 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
714                                                 add_trace("port", NULL, "%d", ifport->portnum);
715                                                 add_trace("position", NULL, "%d", index);
716                                                 add_trace("channel", NULL, "%d", *channel);
717                                                 end_trace();
718                                                 break;
719                                         }
720                                         i++;
721                                 }
722                                 if (*channel)
723                                         break;
724                                 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
725                                 add_trace("port", NULL, "%d", ifport->portnum);
726                                 add_trace("position", NULL, "%d", index);
727                                 end_trace();
728                                 break;
729
730                                 case CHANNEL_ANY: /* don't ask for channel */
731                                 if (mISDNport->b_reserved >= mISDNport->b_num) {
732                                         trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
733                                         add_trace("port", NULL, "%d", ifport->portnum);
734                                         add_trace("position", NULL, "%d", index);
735                                         add_trace("total", NULL, "%d", mISDNport->b_num);
736                                         add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
737                                         end_trace();
738                                         break; /* all channel in use or reserverd */
739                                 }
740                                 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
741                                 add_trace("port", NULL, "%d", ifport->portnum);
742                                 add_trace("position", NULL, "%d", index);
743                                 end_trace();
744                                 *channel = CHANNEL_ANY;
745                                 break;
746
747                                 case CHANNEL_NO: /* call waiting */
748                                 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
749                                 add_trace("port", NULL, "%d", ifport->portnum);
750                                 add_trace("position", NULL, "%d", index);
751                                 end_trace();
752                                 *channel = CHANNEL_NO;
753                                 break;
754
755                                 default:
756                                 if (selchannel->channel<1 || selchannel->channel==16) {
757                                         trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
758                                         add_trace("port", NULL, "%d", ifport->portnum);
759                                         add_trace("position", NULL, "%d", index);
760                                         add_trace("channel", NULL, "%d", selchannel->channel);
761                                         end_trace();
762                                         break; /* invalid channels */
763                                 }
764                                 i = selchannel->channel-1-(selchannel->channel>=17);
765                                 if (i >= mISDNport->b_num) {
766                                         trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
767                                         add_trace("port", NULL, "%d", ifport->portnum);
768                                         add_trace("position", NULL, "%d", index);
769                                         add_trace("channel", NULL, "%d", selchannel->channel);
770                                         add_trace("channels", NULL, "%d", mISDNport->b_num);
771                                         end_trace();
772                                         break; /* channel not in port */
773                                 }
774                                 if (mISDNport->b_port[i] == NULL) {
775                                         *channel = selchannel->channel;
776                                         trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
777                                         add_trace("port", NULL, "%d", ifport->portnum);
778                                         add_trace("position", NULL, "%d", index);
779                                         add_trace("channel", NULL, "%d", *channel);
780                                         end_trace();
781                                         break;
782                                 }
783                                 break;
784                         }
785                         if (*channel)
786                                 break; /* found channel */
787                         selchannel = selchannel->next;
788                 }
789         }
790
791         /* if channel was found, return mISDNport and channel */
792         if (*channel) {
793                 /* setting next port to start next time */
794                 if (interface->hunt == HUNT_ROUNDROBIN) {
795                         index++;
796                         if (!ifport->next)
797                                 index = 0;
798                         interface->hunt_next = index;
799                 }
800                 
801                 return(mISDNport);
802         }
803
804         trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
805         add_trace("port", NULL, "%d", ifport->portnum);
806         add_trace("position", NULL, "%d", index);
807         end_trace();
808
809         portbusy:
810         /* go next port, until all ports are checked */
811         index++;
812         ifport = ifport->next;
813         if (!ifport) {
814                 index = 0;
815                 ifport = interface->ifport;
816         }
817         if (ifport != ifport_start)
818                 goto nextport;
819
820         if (!ifname) {
821                 interface = interface->next;
822                 goto checknext;
823         }
824
825         return(NULL); /* no port found */
826 }
827
828 /* outgoing setup to port(s)
829  * ports will be created and a setup is sent if everything is ok. otherwhise
830  * the endpoint is destroyed.
831  */
832 void EndpointAppPBX::out_setup(void)
833 {
834         struct dialing_info     dialinginfo;
835         class Port              *port;
836         struct port_list        *portlist;
837         struct lcr_msg          *message;
838         int                     anycall = 0;
839         int                     cause = CAUSE_RESSOURCEUNAVAIL;
840         const char              *p;
841         char                    cfp[64];
842         struct mISDNport        *mISDNport;
843         char                    portname[32];
844         char                    *dirname;
845         class EndpointAppPBX    *atemp;
846 //      char                    allowed_ports[256];
847 //      char                    exten[256];
848         char                    ifname[sizeof(e_ext.interfaces)],
849                                 number[256];
850         struct port_settings    port_settings;
851         int                     channel = 0;
852         int                     earlyb;
853         int                     mode = B_MODE_TRANSPARENT;
854
855         /* set bchannel mode */
856         mode = e_capainfo.source_mode;
857
858         /* create settings for creating port */
859         memset(&port_settings, 0, sizeof(port_settings));
860         if (e_ext.tones_dir)
861                 SCPY(port_settings.tones_dir, e_ext.tones_dir);
862         else
863                 SCPY(port_settings.tones_dir, options.tones_dir);
864         port_settings.no_seconds = e_ext.no_seconds;
865         
866         /* 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 */
867
868         /* check what dialinginfo.itype we got */
869         switch(e_dialinginfo.itype) {
870                 /* *********************** call to extension or vbox */
871                 case INFO_ITYPE_ISDN_EXTENSION:
872                 /* check if we deny incoming calls when we use an extension */
873                 if (e_ext.noknocking) {
874                         atemp = apppbx_first;
875                         while(atemp) {
876                                 if (atemp != this)
877                                 if (!strcmp(atemp->e_ext.number, e_ext.number))
878                                         break;
879                                 atemp = atemp->next;
880                         }
881                         if (atemp) {
882                                 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
883                                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
884                                 return; /* must exit here */
885                         }
886                 }
887                 /* FALL THROUGH !!!! */
888                 case INFO_ITYPE_VBOX:
889                 /* get dialed extension's info */
890 //              SCPY(exten, e_dialinginfo.id);
891 //              if (strchr(exten, ','))
892 //                      *strchr(exten, ',') = '\0';
893 //              if (!read_extension(&e_ext, exten))
894                 if (!read_extension(&e_ext, e_dialinginfo.id)) {
895                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
896                         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
897                         return; /* must exit here */
898                 }
899                 e_dialinginfo.sending_complete = 1;
900
901                 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
902                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
903                         p = "vbox";
904                         goto vbox_only;
905                 }
906
907                 /* string from unconditional call forward (cfu) */
908                 p = e_ext.cfu;
909                 if (*p) {
910                         /* present to forwarded party */
911                         if (e_ext.anon_ignore && e_callerinfo.id[0]) {
912                                 e_callerinfo.present = INFO_PRESENT_ALLOWED;
913                         }
914                         if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
915                                 goto cfu_only;
916                 }
917
918                 /* string from busy call forward (cfb) */
919                 p = e_ext.cfb;
920                 if (*p) {
921                         class EndpointAppPBX *checkapp = apppbx_first;
922                         while(checkapp) {
923                                 if (checkapp != this) { /* any other endpoint except our own */
924                                         if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
925                                                 /* present to forwarded party */
926                                                 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
927                                                         e_callerinfo.present = INFO_PRESENT_ALLOWED;
928                                                 }
929                                                 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
930                                                         goto cfb_only;
931                                         }
932                                 }
933                                 checkapp = checkapp->next;
934                         }
935                 }
936
937                 /* string from no-response call forward (cfnr) */
938                 p = e_ext.cfnr;
939                 if (*p) {
940                         /* when cfnr is done, out_setup() will setup the call */
941                         if (e_cfnr_call_timeout.active) {
942                                 /* present to forwarded party */
943                                 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
944                                         e_callerinfo.present = INFO_PRESENT_ALLOWED;
945                                 }
946                                 goto cfnr_only;
947                         }
948                         if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
949                                 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
950                                 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
951                                 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);
952                         }
953                 }
954
955                 /* call to all internal interfaces */
956                 p = e_ext.interfaces;
957                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
958                 while(*p) {
959                         ifname[0] = '\0';
960                         while(*p!=',' && *p!='\0')
961                                 if (*p > ' ')
962                                         SCCAT(ifname, *p++);
963                         if (*p == ',')
964                                 p++;
965                         /* found interface */
966                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
967                         /* hunt for mISDNport and create Port */
968                         mISDNport = hunt_port(ifname, &channel);
969                         if (!mISDNport) {
970                                 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
971                                 add_trace("interface", NULL, "%s", ifname);
972                                 end_trace();
973                                 continue;
974                         }
975                         /* creating INTERNAL port */
976                         SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
977 #ifdef WITH_SS5
978                         if (mISDNport->ss5)
979                                 port = ss5_hunt_line(mISDNport);
980                         else
981 #endif
982                         if (!mISDNport->gsm)
983                                 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
984                         else
985 #ifdef WITH_GSM
986                                 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
987 #else
988                                 port = NULL;
989 #endif
990                         if (!port)
991                                 FATAL("No memory for Port instance\n");
992                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
993                         memset(&dialinginfo, 0, sizeof(dialinginfo));
994                         SCPY(dialinginfo.id, e_dialinginfo.id);
995                         dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
996                         dialinginfo.ntype = e_dialinginfo.ntype;
997                         /* create port_list relation */
998                         portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
999                         if (!portlist) {
1000                                 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1001                                 delete port;
1002                                 goto check_anycall_intern;
1003                         }
1004                         /* directory.list */
1005                         if (e_callerinfo.id[0] && e_ext.display_name) {
1006                                 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1007                                 if (dirname)
1008                                         SCPY(e_callerinfo.name, dirname);
1009                         }
1010 //                      dss1 = (class Pdss1 *)port;
1011                         /* message */
1012 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1013                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1014                         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1015                         memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1016                         memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1017                         memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1018 //terminal                      SCPY(message->param.setup.from_terminal, e_ext.number);
1019 //terminal                      if (e_dialinginfo.id)
1020 //terminal                              SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1021                         /* handle restricted caller ids */
1022                         apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1023                         apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1024                         apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1025                         /* display callerid if desired for extension */
1026                         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));
1027 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1028                         /* use cnip, if enabld */
1029         //              if (!e_ext.centrex)
1030         //                      message->param.setup.callerinfo.name[0] = '\0';
1031                         /* screen clip if prefix is required */
1032                         if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1033                                 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1034                                 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1035                                 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1036                         }
1037                         if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1038                                 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1039                                 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1040                                 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1041                         }
1042                         /* use internal caller id */
1043                         if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1044                                 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1045                                 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1046                                 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1047                         }
1048                         message_put(message);
1049                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1050                         anycall = 1;
1051                 }
1052
1053                 /* string from parallel call forward (cfp) */
1054                 p = e_ext.cfp;
1055                 if (*p) {
1056                         if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1057                                 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1058                                 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1059                         }
1060                 }
1061
1062                 vbox_only: /* entry point for answering machine only */
1063                 cfu_only: /* entry point for cfu */
1064                 cfb_only: /* entry point for cfb */
1065                 cfnr_only: /* entry point for cfnr */
1066                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1067 //              i=0;
1068                 while(*p) {
1069                         earlyb = 0;
1070                         /* only if vbox should be dialed, and terminal is given */
1071                         if (!strcmp(p, "vbox") && e_ext.number[0]) {
1072                                 /* go to the end of p */
1073                                 p += strlen(p);
1074
1075                                 /* answering vbox call */
1076                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1077                                 /* alloc port */
1078                                 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1079                                         FATAL("No memory for VBOX Port instance\n");
1080                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1081                                 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1082                         } else {
1083                                 cfp[0] = '\0';
1084                                 while(*p!=',' && *p!='\0')
1085                                         SCCAT(cfp, *p++);
1086                                 if (*p == ',')
1087                                         p++;
1088                                 /* external call */
1089                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1090                                 /* hunt for mISDNport and create Port */
1091                                 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1092                                 if (mISDNport) {
1093                                         /* creating EXTERNAL port*/
1094                                         SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1095 #ifdef WITH_SS5
1096                                         if (mISDNport->ss5)
1097                                                 port = ss5_hunt_line(mISDNport);
1098                                         else
1099 #endif
1100                                                 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1101                                         if (!port)
1102                                                 FATAL("No memory for Port instance\n");
1103                                         earlyb = mISDNport->earlyb;
1104                                 } else {
1105                                         port = NULL;
1106                                         trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1107                                         add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1108                                         end_trace();
1109                                 }
1110                         }
1111                         if (!port) {
1112                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1113                                 goto check_anycall_intern;
1114                         }
1115                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1116                         memset(&dialinginfo, 0, sizeof(dialinginfo));
1117                         SCPY(dialinginfo.id, cfp);
1118                         dialinginfo.itype = INFO_ITYPE_ISDN;
1119                         dialinginfo.ntype = e_dialinginfo.ntype;
1120                         portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1121                         if (!portlist) {
1122                                 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1123                                 delete port;
1124                                 goto check_anycall_intern;
1125                         }
1126 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1127                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1128                         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1129                         memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1130                         memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1131                         /* if clip is hidden */
1132                         if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1133                                 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1134                                 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1135                                 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1136                                 message->param.setup.callerinfo.present = e_ext.callerid_present;
1137                                 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1138                         }
1139                         memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1140 //terminal                      SCPY(message->param.setup.from_terminal, e_ext.number);
1141 //terminal                      if (e_dialinginfo.id)
1142 //terminal                              SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1143                                 /* handle restricted caller ids */
1144                         apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1145                         apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1146                         apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1147                         /* display callerid if desired for extension */
1148                         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));
1149                         message_put(message);
1150                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1151                         anycall = 1;
1152                 }
1153
1154                 check_anycall_intern:
1155                 /* now we have all ports created */
1156                 if (!anycall) {
1157                         trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1158                         end_trace();
1159                         if (!ea_endpoint->ep_join_id)
1160                                 break;
1161                         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1162                         return; /* must exit here */
1163                 }
1164                 break;
1165
1166                 /* *********************** external call */
1167                 default:
1168                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1169                 /* call to extenal interfaces */
1170                 if (e_dialinginfo.keypad[0])
1171                         p = e_dialinginfo.keypad;
1172                 else
1173                         p = e_dialinginfo.id;
1174                 do {
1175                         number[0] = '\0';
1176                         while(*p!=',' && *p!='\0')
1177                                 SCCAT(number, *p++);
1178                         if (*p == ',')
1179                                 p++;
1180                         /* found number */
1181                         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");
1182                         /* hunt for mISDNport and create Port */
1183                         /* hunt for mISDNport and create Port */
1184                         mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1185                         if (!mISDNport) {
1186                                 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1187                                 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1188                                 end_trace();
1189                                 goto check_anycall_extern;
1190                         }
1191                         /* creating EXTERNAL port*/
1192                         SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1193 #ifdef WITH_SS5
1194                         if (mISDNport->ss5)
1195                                 port = ss5_hunt_line(mISDNport);
1196                         else
1197 #endif
1198                         if (!mISDNport->gsm)
1199                                 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1200                         else
1201 #ifdef WITH_GSM
1202                                 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1203 #else
1204                                 port = NULL;
1205 #endif
1206                         if (!port)
1207                                 FATAL("No memory for Port instance\n");
1208                         earlyb = mISDNport->earlyb;
1209                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1210                         memset(&dialinginfo, 0, sizeof(dialinginfo));
1211                         if (e_dialinginfo.keypad[0])
1212                                 SCPY(dialinginfo.keypad, number);
1213                         else
1214                                 SCPY(dialinginfo.id, number);
1215                         dialinginfo.itype = INFO_ITYPE_ISDN;
1216                         dialinginfo.ntype = e_dialinginfo.ntype;
1217                         dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1218                         portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1219                         if (!portlist) {
1220                                 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1221                                 delete port;
1222                                 goto check_anycall_extern;
1223                         }
1224 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1225                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1226                         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1227                         memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1228                         memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1229                         memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1230 //terminal                      SCPY(message->param.setup.from_terminal, e_ext.number);
1231 //terminal                      if (e_dialinginfo.id)
1232 //terminal                              SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1233                                 /* handle restricted caller ids */
1234                         apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1235                         apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1236                         apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1237                         /* display callerid if desired for extension */
1238                         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));
1239                         message_put(message);
1240                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1241                         anycall = 1;
1242                 } while(*p);
1243
1244                 check_anycall_extern:
1245                 /* now we have all ports created */
1246                 if (!anycall) {
1247                         trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1248                         end_trace();
1249                         if (!ea_endpoint->ep_join_id)
1250                                 break;
1251                         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1252                         return; /* must exit here */
1253                 }
1254                 break;
1255         }
1256
1257 }
1258
1259 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1260 {
1261         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1262
1263         if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1264                 return 0;
1265
1266         unsched_timer(&ea->e_redial_timeout);
1267         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1268         ea->e_multipoint_cause = 0;
1269         ea->e_multipoint_location = 0;
1270         ea->new_state(EPOINT_STATE_IN_OVERLAP);
1271         ea->e_join_pattern = 0;
1272         ea->process_dialing(1);
1273         /* we must exit, because our endpoint might be gone */
1274
1275         return 0;
1276 }
1277
1278 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1279 {
1280         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1281
1282         if (!ea->e_action) {
1283                 unsched_timer(&ea->e_redial_timeout);
1284                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1285                 ea->process_dialing(0);
1286                 /* we must exit, because our endpoint might be gone */
1287         }
1288
1289         return 0;
1290 }
1291
1292 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1293 {
1294         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1295
1296         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1297
1298         ea->new_state(EPOINT_STATE_OUT_SETUP);
1299         /* call special setup routine */
1300         ea->out_setup();
1301
1302         return 0;
1303 }
1304
1305 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1306 {
1307         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1308
1309         /* leave power dialing on */
1310         ea->e_powerdial_on = 1;
1311         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1312
1313         /* redial */
1314         ea->e_ruleset = ruleset_main;
1315         if (ea->e_ruleset)
1316                 ea->e_rule = ea->e_ruleset->rule_first;
1317         ea->e_action = NULL;
1318         ea->new_state(EPOINT_STATE_IN_OVERLAP);
1319         ea->process_dialing(0);
1320
1321         return 0;
1322 }
1323
1324 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1325 {
1326         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1327         struct port_list *portlist;
1328         struct lcr_msg *message;
1329
1330         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1331
1332         /* release all ports */
1333         while((portlist = ea->ea_endpoint->ep_portlist)) {
1334                 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1335                 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1336                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1337                 message_put(message);
1338                 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1339                 ea->ea_endpoint->free_portlist(portlist);
1340         }
1341         /* put on hold */
1342         message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1343         message->param.audiopath = 0;
1344         message_put(message);
1345         /* indicate no patterns */
1346         message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1347         message_put(message);
1348         /* set setup state, since we have no response from the new join */
1349         ea->new_state(EPOINT_STATE_OUT_SETUP);
1350
1351         return 0;
1352 }
1353
1354 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1355 {
1356         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1357
1358         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr);
1359         ea->out_setup();
1360
1361         return 0;
1362 }
1363
1364 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1365 {
1366         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1367
1368         if (ea->e_state == EPOINT_STATE_IDLE) {
1369                 /* epoint is idle, check callback */
1370                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1371                 ea->new_state(EPOINT_STATE_OUT_SETUP);
1372                 ea->out_setup();
1373         }
1374
1375         return 0;
1376 }
1377
1378 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1379 {
1380         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1381
1382         if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1383                 struct port_list *portlist;
1384
1385                 ea->e_ruleset = ruleset_main;
1386                 if (ea->e_ruleset)
1387                         ea->e_rule = ea->e_ruleset->rule_first;
1388                 ea->e_action = NULL;
1389                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1390                 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1391                 end_trace();
1392                 ea->e_connectedmode = 0;
1393                 ea->e_dtmf = 0;
1394                 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1395                 portlist = ea->ea_endpoint->ep_portlist;
1396                 if (portlist) {
1397                         ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1398                         ea->set_tone(portlist, "cause_10");
1399                 }
1400         }
1401
1402         return 0;
1403 }
1404
1405 /* doing a hookflash */
1406 void EndpointAppPBX::hookflash(void)
1407 {
1408         class Port *port;
1409         time_t now;
1410
1411         /* be sure that we are active */
1412         notify_active();
1413         e_tx_state = NOTIFY_STATE_ACTIVE;
1414
1415         trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1416         end_trace();
1417         if (ea_endpoint->ep_use > 1) {
1418                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1419                 return;
1420         }
1421         /* dialtone after pressing the hash key */
1422         process_hangup(e_join_cause, e_join_location);
1423         e_multipoint_cause = 0;
1424         e_multipoint_location = 0;
1425         port = find_port_id(ea_endpoint->ep_portlist->port_id);
1426         if (port) {
1427                 port->set_echotest(0);
1428         }
1429         if (ea_endpoint->ep_join_id) {
1430                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1431         }
1432         e_ruleset = ruleset_main;
1433         if (e_ruleset)
1434                 e_rule = e_ruleset->rule_first;
1435         e_action = NULL;
1436         new_state(EPOINT_STATE_IN_OVERLAP);
1437         e_connectedmode = 1;
1438         SCPY(e_dialinginfo.id, e_ext.prefix);
1439         e_extdialing = e_dialinginfo.id;
1440         e_join_pattern = 0;
1441         if (e_dialinginfo.id[0]) {
1442                 set_tone(ea_endpoint->ep_portlist, "dialing");
1443                 process_dialing(0);
1444         } else {
1445                 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1446         }
1447         time(&now);
1448         e_dtmf_time = now;
1449         e_dtmf_last = '\0';
1450 }
1451
1452
1453 /* messages from port
1454  */
1455 /* port MESSAGE_SETUP */
1456 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1457 {
1458         struct lcr_msg          *message;
1459         char                    buffer[256];
1460         int                     writeext;               /* flags need to write extension after modification */
1461         class Port              *port;
1462         struct interface        *interface;
1463
1464         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1465         
1466         portlist->port_type = param->setup.port_type;
1467         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
1468         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
1469         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
1470         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
1471
1472         /* convert (inter-)national number type */
1473         SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1474         e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1475
1476 //      e_dtmf = param->setup.dtmf;
1477         /* screen incoming caller id */
1478         interface = interface_first;
1479         while(interface) {
1480                 if (!strcmp(e_callerinfo.interface, interface->name)) {
1481                         break;
1482                 }
1483                 interface = interface->next;
1484         }
1485         if (interface) {
1486                 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1487                 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1488         }
1489
1490         /* process extension */
1491         if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1492                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1493                 /* port makes call from extension */
1494                 SCPY(e_callerinfo.extension, e_callerinfo.id);
1495                 SCPY(e_ext.number, e_callerinfo.extension);
1496                 SCPY(e_extension_interface, e_callerinfo.interface);
1497         } else {
1498                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1499         }
1500
1501         if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1502                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1503
1504                 /* get extension's info about caller */
1505                 if (!read_extension(&e_ext, e_ext.number)) {
1506                         /* extension doesn't exist */
1507                         trace_header("EXTENSION (not created)", DIRECTION_IN);
1508                         add_trace("extension", NULL, "%s", e_ext.number);
1509                         end_trace();
1510                         message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1511                         new_state(EPOINT_STATE_OUT_DISCONNECT);
1512                         set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1513                         e_ext.number[0] = '\0'; /* no terminal */
1514                         return;
1515                 }
1516                 writeext = 0;
1517
1518                 /* put prefix (next) in front of e_dialinginfo.id */
1519                 if (e_ext.next[0]) {
1520                         SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1521                         SCPY(e_dialinginfo.id, buffer);
1522                         e_ext.next[0] = '\0';
1523                         writeext = 1;
1524                 } else if (e_ext.prefix[0]) {
1525                         SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1526                         SCPY(e_dialinginfo.id, buffer);
1527                 }
1528
1529                 /* screen caller id by extension's config */
1530                 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1531                 if (e_ext.name[0])
1532                         SCPY(e_callerinfo.name, e_ext.name);
1533                 /* use caller id (or if exist: id_next_call) for this call */
1534                 if (e_ext.id_next_call_present >= 0) {
1535                         SCPY(e_callerinfo.id, e_ext.id_next_call);
1536                         /* if we restrict the pesentation */
1537                         if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1538                                 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1539                         else    e_callerinfo.present = e_ext.id_next_call_present;
1540                         e_callerinfo.ntype = e_ext.id_next_call_type;
1541                         e_ext.id_next_call_present = -1;
1542                         writeext = 1;
1543                 } else {
1544                         SCPY(e_callerinfo.id, e_ext.callerid);
1545                         /* if we restrict the pesentation */
1546                         if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1547                                 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1548                         else    e_callerinfo.present = e_ext.callerid_present;
1549                         e_callerinfo.ntype = e_ext.callerid_type;
1550                 }
1551                 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1552
1553                 /* extension is written */
1554                 if (writeext)
1555                         write_extension(&e_ext, e_ext.number);
1556
1557                 /* set volume of rx and tx */
1558                 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1559                 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1560                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1561                         message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1562                         message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1563                         message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1564                         message_put(message);
1565                 }
1566
1567                 /* start recording if enabled */
1568                 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1569                         /* check if we are a terminal */
1570                         if (e_ext.number[0] == '\0')
1571                                 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1572                         else {
1573                                 port = find_port_id(portlist->port_id);
1574                                 if (port)
1575                                         port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1576                         }
1577                 }
1578         } else {
1579                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1580                 /* no terminal identification */
1581                 e_ext.number[0] = '\0';
1582                 e_extension_interface[0] = '\0';
1583                 memset(&e_ext, 0, sizeof(e_ext));
1584                 e_ext.rights = 4; /* right to dial internat */
1585         }
1586
1587         /* incoming call */
1588         e_ruleset = ruleset_main;
1589         if (e_ruleset)
1590                 e_rule = e_ruleset->rule_first;
1591         e_action = NULL;
1592         e_extdialing = e_dialinginfo.id;
1593         new_state(EPOINT_STATE_IN_SETUP);
1594         if (e_dialinginfo.id[0]) {
1595                 set_tone(portlist, "dialing");
1596         } else {
1597                 if (e_ext.number[0])
1598                         set_tone(portlist, "dialpbx");
1599                 else
1600                         set_tone(portlist, "dialtone");
1601         }
1602         process_dialing(0);
1603         if (e_state == EPOINT_STATE_IN_SETUP) {
1604                 /* request MORE info, if not already at higher state */
1605                 new_state(EPOINT_STATE_IN_OVERLAP);
1606                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1607                 message_put(message);
1608                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1609         }
1610 }
1611
1612 /* port MESSAGE_INFORMATION */
1613 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1614 {
1615         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1616
1617         /* ignore information message without digit information */
1618         if (!param->information.id[0])
1619                 return;
1620
1621         e_overlap = 1;
1622
1623         /* turn off dtmf detection, in case dtmf is sent with keypad information */
1624         if (e_dtmf) {
1625                 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1626                 end_trace();
1627                 e_dtmf = 0;
1628         }
1629
1630         /* if vbox_play is done, the information are just used as they come */
1631         if (e_action)
1632         if (e_action->index == ACTION_VBOX_PLAY) {
1633                 /* concat dialing string */
1634                 SCAT(e_dialinginfo.id, param->information.id);
1635                 process_dialing(0);
1636                 return;
1637         }
1638
1639         /* keypad when disconnect but in connected mode */
1640         if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1641                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1642                 /* processing keypad function */
1643                 if (param->information.id[0] == '0') {
1644                         hookflash();
1645                 }
1646                 return;
1647         }
1648
1649         /* keypad when connected */
1650         if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1651                 if (e_ext.keypad || e_enablekeypad) {
1652                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1653                         /* processing keypad function */
1654                         if (param->information.id[0] == '0') {
1655                                 hookflash();
1656                         }
1657                         if (param->information.id[0])
1658                                 keypad_function(param->information.id[0]);
1659                 } else {
1660                         if (e_ext.number[0])
1661                                 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1662                         else
1663                                 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1664                         end_trace();
1665                 }
1666                 return;
1667         }
1668         if (e_state != EPOINT_STATE_IN_OVERLAP) {
1669                 if (e_ext.number[0])
1670                         trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1671                 else
1672                         trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1673                 end_trace();
1674                 return;
1675         }
1676         if (!param->information.id[0])
1677                 return;
1678         if (e_dialinginfo.id[0]=='\0' && !e_action) {
1679                 set_tone(portlist, "dialing");
1680         }
1681         if (e_action)
1682         if (e_action->index==ACTION_OUTDIAL
1683          || e_action->index==ACTION_EXTERNAL
1684          || e_action->index==ACTION_REMOTE) {
1685                 if (!e_extdialing)
1686                         set_tone(portlist, "dialing");
1687                 else if (!e_extdialing[0])
1688                         set_tone(portlist, "dialing");
1689         }
1690         /* concat dialing string */
1691         SCAT(e_dialinginfo.id, param->information.id);
1692         process_dialing(0);
1693 }
1694
1695 /* port MESSAGE_DTMF */
1696 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1697 {
1698         time_t now;
1699
1700         time(&now);
1701
1702         /* only if dtmf detection is enabled */
1703         if (!e_dtmf) {
1704                 trace_header("DTMF (disabled)", DIRECTION_IN);
1705                 end_trace();
1706                 return;
1707         }
1708         trace_header("DTMF", DIRECTION_IN);
1709         add_trace("digit", NULL, "%c", param->dtmf);
1710         end_trace();
1711
1712 #if 0
1713 NOTE: vbox is now handled due to overlap state
1714         /* if vbox_play is done, the dtmf digits are just used as they come */
1715         if (e_action)
1716         if (e_action->index == ACTION_VBOX_PLAY) {
1717                 /* concat dialing string */
1718                 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1719                         e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1720                         e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1721                         process_dialing(0);
1722                 }
1723                 /* continue to process *X# sequences */
1724         }
1725 #endif
1726
1727         /* check for *X# sequence */
1728         if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1729                 if (e_dtmf_time+3 < now) {
1730                         /* the last digit was too far in the past to be a sequence */
1731                         if (param->dtmf == '*')
1732                                 /* only start is allowed in the sequence */
1733                                 e_dtmf_last = '*';
1734                         else
1735                                 e_dtmf_last = '\0';
1736                 } else {
1737                         /* we have a sequence of digits, see what we got */
1738                         if (param->dtmf == '*')
1739                                 e_dtmf_last = '*';
1740                         else if (param->dtmf>='0' && param->dtmf<='9') {
1741                                 /* we need to have a star before we receive the digit of the sequence */
1742                                 if (e_dtmf_last == '*')
1743                                         e_dtmf_last = param->dtmf;
1744                         } else if (param->dtmf == '#') {
1745                                 /* the hash key */
1746                                 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1747                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1748                                         if (e_dtmf_last == '0') {
1749                                                 hookflash();
1750                                                 return;
1751                                         }
1752                                         /* processing keypad function */
1753                                         if (param->dtmf)
1754                                                 keypad_function(e_dtmf_last);
1755                                         e_dtmf_last = '\0';
1756                                 }
1757                         }
1758                 }
1759
1760                 /* set last time of dtmf */
1761                 e_dtmf_time = now;
1762                 return;
1763         }
1764
1765         /* check for ## hookflash during dialing */
1766         if (e_action)
1767         if (e_action->index==ACTION_PASSWORD
1768          || e_action->index==ACTION_PASSWORD_WRITE)
1769                 goto password;
1770         if (param->dtmf=='#') { /* current digit is '#' */
1771                 if (e_state==EPOINT_STATE_IN_DISCONNECT
1772                  || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1773                         hookflash();
1774                         return;
1775                 } else {
1776                         e_dtmf_time = now;
1777                         e_dtmf_last = '#';
1778                 }
1779         } else {
1780                 password:
1781                 e_dtmf_time = now;
1782                 e_dtmf_last = '\0';
1783         }
1784         
1785
1786         /* dialing using dtmf digit */
1787         if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1788                 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1789                         set_tone(portlist, "dialing");
1790                 }
1791                 /* concat dialing string */
1792                 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1793                         e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1794                         e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1795                         process_dialing(0);
1796                 }
1797         }
1798 }
1799
1800 /* port MESSAGE_CRYPT */
1801 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1802 {
1803         /* send crypt response to cryptman */
1804         if (param->crypt.type == CR_MESSAGE_IND)
1805                 cryptman_msg2man(param->crypt.data, param->crypt.len);
1806         else
1807                 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1808 }
1809
1810 /* port MESSAGE_OVERLAP */
1811 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1812 {
1813         struct lcr_msg *message;
1814
1815         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1816
1817         /* signal to call tool */
1818         admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1819
1820         if (e_dialing_queue[0] && portlist) {
1821                 /* send what we have not dialed yet, because we had no setup complete */
1822                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1823                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1824                 SCPY(message->param.information.id, e_dialing_queue);
1825                 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1826                 message_put(message);
1827                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1828                 e_dialing_queue[0] = '\0';
1829         }
1830         /* check if pattern is available */
1831         if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1832                 /* indicate patterns */
1833                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1834                 message_put(message);
1835
1836                 /* connect audio, if not already */
1837                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1838                 message->param.audiopath = 1;
1839                 message_put(message);
1840         } else {
1841                 /* indicate no patterns */
1842                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1843                 message_put(message);
1844
1845                 /* disconnect audio, if not already */
1846                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1847                 message->param.audiopath = 0;
1848                 message_put(message);
1849         }
1850         new_state(EPOINT_STATE_OUT_OVERLAP);
1851         /* if we are in a join */
1852         if (ea_endpoint->ep_join_id) { 
1853                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1854                 memcpy(&message->param, param, sizeof(union parameter));
1855                 message_put(message);
1856         }
1857 }
1858
1859 /* port MESSAGE_PROCEEDING */
1860 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1861 {
1862         struct lcr_msg *message;
1863
1864         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1865
1866         /* signal to call tool */
1867         admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1868
1869         e_state = EPOINT_STATE_OUT_PROCEEDING;
1870         /* check if pattern is availatle */
1871         if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1872                 /* indicate patterns */
1873                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1874                 message_put(message);
1875
1876                 /* connect audio, if not already */
1877                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1878                 message->param.audiopath = 1;
1879                 message_put(message);
1880         } else {
1881                 /* indicate no patterns */
1882                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1883                 message_put(message);
1884
1885                 /* disconnect audio, if not already */
1886                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1887                 message->param.audiopath = 0;
1888                 message_put(message);
1889         }
1890         /* if we are in a call */
1891         if (ea_endpoint->ep_join_id) { 
1892                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1893                 memcpy(&message->param, param, sizeof(union parameter));
1894                 message_put(message);
1895         }
1896 }
1897
1898 /* port MESSAGE_ALERTING */
1899 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1900 {
1901         struct lcr_msg *message;
1902
1903         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1904
1905         /* signal to call tool */
1906         admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1907 //#warning hack!!
1908 //      if (e_adminid)
1909 //              set_tone(portlist, "hold");
1910
1911         new_state(EPOINT_STATE_OUT_ALERTING);
1912         /* check if pattern is available */
1913         if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1914                 /* indicate patterns */
1915                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1916                 message_put(message);
1917
1918                 /* connect audio, if not already */
1919                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1920                 message->param.audiopath = 1;
1921                 message_put(message);
1922         } else {
1923                 /* indicate no patterns */
1924                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1925                 message_put(message);
1926
1927                 /* disconnect audio, if not already */
1928                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1929                 message->param.audiopath = 0;
1930                 message_put(message);
1931         }
1932         /* if we are in a call */
1933         if (ea_endpoint->ep_join_id) { 
1934                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1935                 memcpy(&message->param, param, sizeof(union parameter));
1936                 message_put(message);
1937         }
1938 }
1939
1940 /* port MESSAGE_CONNECT */
1941 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1942 {
1943         struct lcr_msg *message;
1944         char buffer[256];
1945         unsigned int port_id = portlist->port_id;
1946         struct port_list *tportlist;
1947         class Port *port;
1948         struct interface        *interface;
1949         time_t now;
1950
1951         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1952
1953         /* signal to call tool */
1954         admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1955
1956         memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_connectinfo));
1957         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1958         while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1959                 tportlist = ea_endpoint->ep_portlist;
1960                 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1961                         tportlist = tportlist->next;
1962                 if (tportlist->port_id == port_id)
1963                         FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1964                 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1965                 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1966                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1967                 message_put(message);
1968                 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1969                 ea_endpoint->free_portlist(tportlist);
1970         }
1971         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1972
1973         time(&now);
1974         e_start = now;
1975
1976         /* screen incoming connected id */
1977         interface = interface_first;
1978         while(interface) {
1979                 if (!strcmp(e_connectinfo.interface, interface->name)) {
1980                         break;
1981                 }
1982                 interface = interface->next;
1983         }
1984         if (interface)
1985                 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1986
1987         /* screen connected name */
1988         if (e_ext.name[0])
1989                 SCPY(e_connectinfo.name, e_ext.name);
1990
1991         /* add internal id to colp */
1992         SCPY(e_connectinfo.extension, e_ext.number);
1993
1994         /* we store the connected port number */
1995         SCPY(e_extension_interface, e_connectinfo.interface);
1996
1997         /* for internal and am calls, we get the extension's id */
1998         if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1999                 SCPY(e_connectinfo.id, e_ext.callerid);
2000                 SCPY(e_connectinfo.extension, e_ext.number);
2001                 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2002                 e_connectinfo.ntype = e_ext.callerid_type;
2003                 e_connectinfo.present = e_ext.callerid_present;
2004         }
2005         if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2006                 e_connectinfo.itype = INFO_ITYPE_VBOX;
2007                 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2008         }
2009
2010         new_state(EPOINT_STATE_CONNECT);
2011
2012         /* set volume of rx and tx */
2013         if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2014                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2015                 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2016                 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2017                 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2018                 message_put(message);
2019         }
2020
2021         unsched_timer(&e_cfnr_timeout);
2022         unsched_timer(&e_cfnr_call_timeout);
2023         if (e_ext.number[0])
2024                 e_dtmf = 1; /* allow dtmf */
2025
2026         /* modify colp */
2027         /* other calls with no caller id (or not available for the extension) and force colp */
2028         if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2029                 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2030                 if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT || portlist->port_type==PORT_TYPE_GSM_OUT) { /* external extension answered */
2031                         port = find_port_id(portlist->port_id);
2032                         if (port) {
2033                                 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2034                                 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2035                         }
2036                 }
2037         }
2038
2039         /* send connect to join */
2040         if (ea_endpoint->ep_join_id) {
2041                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2042                 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2043                 message_put(message);
2044
2045                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2046                 message->param.audiopath = 1;
2047                 message_put(message);
2048         } else if (!e_adminid) {
2049                 /* callback */
2050                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2051                 SCPY(e_ext.number, e_cbcaller);
2052                 new_state(EPOINT_STATE_IN_OVERLAP);
2053                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2054
2055                 /* get extension's info about terminal */
2056                 if (!read_extension(&e_ext, e_ext.number)) {
2057                         /* extension doesn't exist */
2058                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2059                         message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2060                         new_state(EPOINT_STATE_OUT_DISCONNECT);
2061                         set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2062                         return;
2063                 }
2064
2065                 /* put prefix in front of e_cbdialing */
2066                 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2067                 SCPY(e_dialinginfo.id, buffer);
2068                 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2069                 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2070
2071                 /* use caller id (or if exist: id_next_call) for this call */
2072                 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2073                 SCPY(e_callerinfo.extension, e_ext.number);
2074                 if (e_ext.id_next_call_present >= 0) {
2075                         SCPY(e_callerinfo.id, e_ext.id_next_call);
2076                         e_callerinfo.present = e_ext.id_next_call_present;
2077                         e_callerinfo.ntype = e_ext.id_next_call_type;
2078                         e_ext.id_next_call_present = -1;
2079                         /* extension is written */
2080                         write_extension(&e_ext, e_ext.number);
2081                 } else {
2082                         SCPY(e_callerinfo.id, e_ext.callerid);
2083                         e_callerinfo.present = e_ext.callerid_present;
2084                         e_callerinfo.ntype = e_ext.callerid_type;
2085                 }
2086                 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2087
2088                 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2089                 e_dtmf = 1;
2090
2091                 /* check if caller id is NOT authenticated */
2092                 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2093                         /* make call state to enter password */
2094                         new_state(EPOINT_STATE_IN_OVERLAP);
2095                         e_action = &action_password_write;
2096                         unsched_timer(&e_match_timeout);
2097                         e_match_to_action = NULL;
2098                         e_dialinginfo.id[0] = '\0';
2099                         e_extdialing = strchr(e_dialinginfo.id, '\0');
2100                         schedule_timer(&e_password_timeout, 20, 0);
2101                         process_dialing(0);
2102                 } else {
2103                         /* incoming call (callback) */
2104                         e_ruleset = ruleset_main;
2105                         if (e_ruleset)
2106                                 e_rule = e_ruleset->rule_first;
2107                         e_action = NULL;
2108                         e_extdialing = e_dialinginfo.id;
2109                         if (e_dialinginfo.id[0]) {
2110                                 set_tone(portlist, "dialing");
2111                                 process_dialing(0);
2112                         } else {
2113                                 set_tone(portlist, "dialpbx");
2114                         }
2115                 }
2116         } else { /* testcall */
2117                 set_tone(portlist, "hold");
2118         }
2119
2120         /* start recording if enabled, not when answering machine answers */
2121         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)) {
2122                 /* check if we are a terminal */
2123                 if (e_ext.number[0] == '\0')
2124                         PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2125                 else {
2126                         port = find_port_id(portlist->port_id);
2127                         if (port)
2128                                 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2129                 }
2130         }
2131 }
2132
2133 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2134 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2135 {
2136         struct lcr_msg  *message;
2137         char            buffer[256];
2138         unsigned int    port_id = portlist->port_id;
2139         int             cause,
2140                         location;
2141
2142         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2143
2144         /* signal to call tool */
2145         admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2146
2147 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2148         if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2149                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2150                 return;
2151         }
2152
2153         /* collect cause */
2154         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);
2155         collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2156         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2157
2158         /* check if we have more than one portlist relation and we just ignore the disconnect */
2159         if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2160                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2161                 portlist = ea_endpoint->ep_portlist;
2162                 while(portlist) {
2163                         if (portlist->port_id == port_id)
2164                                 break;
2165                         portlist = portlist->next;
2166                 }
2167                 if (!portlist)
2168                         FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2169                 if (message_type != MESSAGE_RELEASE) {
2170                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2171                         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2172                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2173                         message_put(message);
2174                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2175                 }
2176                 ea_endpoint->free_portlist(portlist);
2177                 return; /* one relation removed */ 
2178         }
2179         if (e_state == EPOINT_STATE_CONNECT) {
2180                 /* use cause from port after connect */
2181                 cause = param->disconnectinfo.cause;
2182                 location = param->disconnectinfo.location;
2183         } else {
2184                 /* use multipoint cause if no connect yet */
2185                 if (e_multipoint_cause) {
2186                         cause = e_multipoint_cause;
2187                         location = e_multipoint_location;
2188                 } else {
2189                         cause = CAUSE_NOUSER;
2190                         location = LOCATION_PRIVATE_LOCAL;
2191                 }
2192         }
2193
2194         unsched_timer(&e_cfnr_timeout);
2195         unsched_timer(&e_cfnr_call_timeout);
2196
2197         /* process hangup */
2198         process_hangup(e_join_cause, e_join_location);
2199         e_multipoint_cause = 0;
2200         e_multipoint_location = 0;
2201
2202         if (message_type == MESSAGE_DISCONNECT) {
2203                 /* tone to disconnected end */
2204                 SPRINT(buffer, "cause_%02x", cause);
2205                 if (ea_endpoint->ep_portlist)
2206                         set_tone(ea_endpoint->ep_portlist, buffer);
2207
2208                 new_state(EPOINT_STATE_IN_DISCONNECT);
2209         }
2210
2211         if (ea_endpoint->ep_join_id) {
2212                 int haspatterns = 0;
2213                 /* check if pattern is available */
2214                 if (ea_endpoint->ep_portlist)
2215                 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2216                 if (joinpbx_countrelations(ea_endpoint->ep_join_id)==2 // we must count relations, in order not to disturb the conference ; NOTE: asterisk always counts two, since it is a point to point call 
2217                  && message_type != MESSAGE_RELEASE) // if we release, we are done
2218                         haspatterns = 1;
2219                 if (haspatterns) {
2220                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2221                         /* indicate patterns */
2222                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2223                         message_put(message);
2224                         /* connect audio, if not already */
2225                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2226                         message->param.audiopath = 1;
2227                         message_put(message);
2228                         /* send disconnect */
2229                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2230                         memcpy(&message->param, param, sizeof(union parameter));
2231                         message_put(message);
2232                         /* disable encryption if disconnected */
2233 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2234                         if (e_crypt_state)
2235                                 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2236                         return;
2237                 } else {
2238                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2239                 }
2240         }
2241         if (message_type == MESSAGE_RELEASE)
2242                 ea_endpoint->free_portlist(portlist);
2243         release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2244         return; /* must exit here */
2245 }
2246
2247 /* port MESSAGE_TIMEOUT */
2248 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2249 {
2250         char cause[16];
2251
2252         trace_header("TIMEOUT", DIRECTION_IN);
2253         message_type = MESSAGE_DISCONNECT;
2254         switch (param->state) {
2255                 case PORT_STATE_OUT_SETUP:
2256                 case PORT_STATE_OUT_OVERLAP:
2257                 add_trace("state", NULL, "outgoing setup/dialing");
2258                 end_trace();
2259                 /* no user responding */
2260                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2261                 return; /* must exit here */
2262
2263                 case PORT_STATE_IN_SETUP:
2264                 case PORT_STATE_IN_OVERLAP:
2265                 add_trace("state", NULL, "incoming setup/dialing");
2266                 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2267                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2268                 break;
2269
2270                 case PORT_STATE_OUT_PROCEEDING:
2271                 add_trace("state", NULL, "outgoing proceeding");
2272                 end_trace();
2273                 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2274                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2275                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2276                 return; /* must exit here */
2277
2278                 case PORT_STATE_IN_PROCEEDING:
2279                 add_trace("state", NULL, "incoming proceeding");
2280                 param->disconnectinfo.cause = CAUSE_NOUSER;
2281                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2282                 break;
2283
2284                 case PORT_STATE_OUT_ALERTING:
2285                 add_trace("state", NULL, "outgoing alerting");
2286                 end_trace();
2287                 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2288                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2289                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2290                 return; /* must exit here */
2291
2292                 case PORT_STATE_CONNECT:
2293                 add_trace("state", NULL, "connect");
2294                 end_trace();
2295                 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2296                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2297                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2298                 return; /* must exit here */
2299
2300                 case PORT_STATE_IN_ALERTING:
2301                 add_trace("state", NULL, "incoming alerting");
2302                 param->disconnectinfo.cause = CAUSE_NOANSWER;
2303                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2304                 break;
2305
2306                 case PORT_STATE_IN_DISCONNECT:
2307                 case PORT_STATE_OUT_DISCONNECT:
2308                 add_trace("state", NULL, "disconnect");
2309                 end_trace();
2310                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2311                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2312                 return; /* must exit here */
2313
2314                 default:
2315                 param->disconnectinfo.cause = 31; /* normal unspecified */
2316                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2317         }
2318         end_trace();
2319         /* release call, disconnect isdn */
2320         e_join_pattern = 0;
2321         new_state(EPOINT_STATE_OUT_DISCONNECT);
2322         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2323         SCPY(e_tone, cause);
2324         while(portlist) {
2325                 set_tone(portlist, cause);
2326                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2327                 portlist = portlist->next;
2328         }
2329         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2330 }
2331
2332 /* port MESSAGE_NOTIFY */
2333 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2334 {
2335         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2336
2337         struct lcr_msg *message;
2338         const char *logtext = "";
2339         char buffer[64];
2340
2341         /* signal to call tool */
2342         admin_call_response(e_adminid, ADMIN_CALL_NOTIFY, numberrize_callerinfo(param->notifyinfo.id,param->notifyinfo.ntype, options.national, options.international), 0, 0, param->notifyinfo.notify);
2343         if (param->notifyinfo.notify) {
2344                 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2345         }
2346
2347         /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2348         if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2349                 case INFO_NOTIFY_REMOTE_HOLD:
2350                 case INFO_NOTIFY_USER_SUSPENDED:
2351                 /* tell call about it */
2352                 if (ea_endpoint->ep_join_id) {
2353                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2354                         message->param.audiopath = 0;
2355                         message_put(message);
2356                 }
2357                 break;
2358
2359                 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2360                 case INFO_NOTIFY_USER_RESUMED:
2361                 /* set volume of rx and tx */
2362                 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2363                 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2364                 if (portlist) {
2365                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2366                         message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2367                         message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2368                         message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2369                         message_put(message);
2370                 }
2371                 /* set current tone */
2372                 if (portlist)
2373                         set_tone(portlist, e_tone);
2374                 /* tell call about it */
2375                 if (ea_endpoint->ep_join_id) {
2376                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2377                         message->param.audiopath = 1;
2378                         message_put(message);
2379                 }
2380                 break;
2381         }
2382
2383         /* get name of notify */
2384         switch(param->notifyinfo.notify) {
2385                 case 0x00:
2386                 logtext = "NULL";
2387                 break;
2388                 case 0x80:
2389                 logtext = "USER_SUSPENDED";
2390                 break;
2391                 case 0x82:
2392                 logtext = "BEARER_SERVICE_CHANGED";
2393                 break;
2394                 case 0x81:
2395                 logtext = "USER_RESUMED";
2396                 break;
2397                 case 0xc2:
2398                 logtext = "CONFERENCE_ESTABLISHED";
2399                 break;
2400                 case 0xc3:
2401                 logtext = "CONFERENCE_DISCONNECTED";
2402                 break;
2403                 case 0xc4:
2404                 logtext = "OTHER_PARTY_ADDED";
2405                 break;
2406                 case 0xc5:
2407                 logtext = "ISOLATED";
2408                 break;
2409                 case 0xc6:
2410                 logtext = "REATTACHED";
2411                 break;
2412                 case 0xc7:
2413                 logtext = "OTHER_PARTY_ISOLATED";
2414                 break;
2415                 case 0xc8:
2416                 logtext = "OTHER_PARTY_REATTACHED";
2417                 break;
2418                 case 0xc9:
2419                 logtext = "OTHER_PARTY_SPLIT";
2420                 break;
2421                 case 0xca:
2422                 logtext = "OTHER_PARTY_DISCONNECTED";
2423                 break;
2424                 case 0xcb:
2425                 logtext = "CONFERENCE_FLOATING";
2426                 break;
2427                 case 0xcc:
2428                 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2429                 break;
2430                 case 0xcf:
2431                 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2432                 break;
2433                 case 0xe0:
2434                 logtext = "CALL_IS_A_WAITING_CALL";
2435                 break;
2436                 case 0xe8:
2437                 logtext = "DIVERSION_ACTIVATED";
2438                 break;
2439                 case 0xe9:
2440                 logtext = "RESERVED_CT_1";
2441                 break;
2442                 case 0xea:
2443                 logtext = "RESERVED_CT_2";
2444                 break;
2445                 case 0xee:
2446                 logtext = "REVERSE_CHARGING";
2447                 break;
2448                 case 0xf9:
2449                 logtext = "REMOTE_HOLD";
2450                 break;
2451                 case 0xfa:
2452                 logtext = "REMOTE_RETRIEVAL";
2453                 break;
2454                 case 0xfb:
2455                 logtext = "CALL_IS_DIVERTING";
2456                 break;
2457                 default:
2458                 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2459                 logtext = buffer;
2460
2461         }
2462
2463         /* notify call if available */
2464         if (ea_endpoint->ep_join_id) {
2465                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2466                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
2467                 message_put(message);
2468         }
2469
2470 }
2471
2472 /* port MESSAGE_PROGRESS */
2473 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2474 {
2475         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2476
2477         struct lcr_msg *message;
2478
2479         /* signal to call tool */
2480         admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2481
2482         /* send progress to call if available */
2483         if (ea_endpoint->ep_join_id) {
2484                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2485                 memcpy(&message->param.progressinfo, &param->progressinfo, sizeof(struct progress_info));
2486                 message_put(message);
2487         }
2488
2489 }
2490
2491 /* port MESSAGE_FACILITY */
2492 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2493 {
2494         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2495
2496         struct lcr_msg *message;
2497
2498         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2499         memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2500         message_put(message);
2501 }
2502
2503 /* port MESSAGE_SUSPEND */
2504 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2505 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2506 {
2507         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2508
2509         /* epoint is now parked */
2510         ea_endpoint->ep_park = 1;
2511         memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2512         ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2513
2514         /* remove port relation */
2515         ea_endpoint->free_portlist(portlist);
2516 }
2517
2518 /* port MESSAGE_RESUME */
2519 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2520 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2521 {
2522         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2523
2524         /* epoint is now resumed */
2525         ea_endpoint->ep_park = 0;
2526
2527 }
2528
2529
2530 /* port sends message to the endpoint
2531  */
2532 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2533 {
2534         struct port_list *portlist;
2535
2536         portlist = ea_endpoint->ep_portlist;
2537         while(portlist) {
2538                 if (port_id == portlist->port_id)
2539                         break;
2540                 portlist = portlist->next;
2541         }
2542         if (!portlist) {
2543                 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);
2544                 return;
2545         }
2546
2547 //      PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2548         switch(message_type) {
2549                 case MESSAGE_DATA: /* data from port */
2550                 /* check if there is a call */
2551                 if (!ea_endpoint->ep_join_id)
2552                         break;
2553                 /* continue if only one portlist */
2554                 if (ea_endpoint->ep_portlist->next != NULL)
2555                         break;
2556                 /* forward message */
2557                 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);  
2558                 break;
2559
2560                 case MESSAGE_TONE_EOF: /* tone is end of file */
2561                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2562                 if (e_action) {
2563                         if (e_action->index == ACTION_VBOX_PLAY) {
2564                                 vbox_message_eof();
2565                         }
2566                         if (e_action->index == ACTION_EFI) {
2567                                 efi_message_eof();
2568                         }
2569                 }
2570                 break;
2571
2572                 case MESSAGE_TONE_COUNTER: /* counter info received */
2573                 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);
2574                 if (e_action)
2575                 if (e_action->index == ACTION_VBOX_PLAY) {
2576                         e_vbox_counter = param->counter.current;
2577                         if (param->counter.max >= 0)
2578                                 e_vbox_counter_max = param->counter.max;
2579                 }
2580                 break;
2581
2582                 /* PORT sends SETUP message */
2583                 case MESSAGE_SETUP:
2584                 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);
2585                 if (e_state!=EPOINT_STATE_IDLE) {
2586                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2587                         break;
2588                 }
2589                 port_setup(portlist, message_type, param);
2590                 break;
2591
2592                 /* PORT sends INFORMATION message */
2593                 case MESSAGE_INFORMATION: /* additional digits received */
2594                 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);
2595                 port_information(portlist, message_type, param);
2596                 break;
2597
2598                 /* PORT sends FACILITY message */
2599                 case MESSAGE_FACILITY:
2600                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2601                 port_facility(portlist, message_type, param);
2602                 break;
2603
2604                 /* PORT sends DTMF message */
2605                 case MESSAGE_DTMF: /* dtmf digits received */
2606                 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);
2607                 port_dtmf(portlist, message_type, param);
2608                 break;
2609
2610                 /* PORT sends CRYPT message */
2611                 case MESSAGE_CRYPT: /* crypt response received */
2612                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2613                 port_crypt(portlist, message_type, param);
2614                 break;
2615
2616                 /* PORT sends MORE message */
2617                 case MESSAGE_OVERLAP:
2618                 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);
2619                 if (e_state != EPOINT_STATE_OUT_SETUP) {
2620                         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);
2621                         break;
2622                 }
2623                 port_overlap(portlist, message_type, param);
2624                 break;
2625
2626                 /* PORT sends PROCEEDING message */
2627                 case MESSAGE_PROCEEDING: /* port is proceeding */
2628                 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);
2629                 if (e_state!=EPOINT_STATE_OUT_SETUP
2630                  && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2631                         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);
2632                         break;
2633                 }
2634                 port_proceeding(portlist, message_type, param);
2635                 break;
2636
2637                 /* PORT sends ALERTING message */
2638                 case MESSAGE_ALERTING:
2639                 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);
2640                 if (e_state!=EPOINT_STATE_OUT_SETUP
2641                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2642                  && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2643                         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);
2644                         break;
2645                 }
2646                 port_alerting(portlist, message_type, param);
2647                 break;
2648
2649                 /* PORT sends CONNECT message */
2650                 case MESSAGE_CONNECT:
2651                 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);
2652                 if (e_state!=EPOINT_STATE_OUT_SETUP
2653                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2654                  && e_state!=EPOINT_STATE_OUT_PROCEEDING
2655                  && e_state!=EPOINT_STATE_OUT_ALERTING) {
2656                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2657                         break;
2658                 }
2659                 port_connect(portlist, message_type, param);
2660                 break;
2661
2662                 /* PORT sends DISCONNECT message */
2663                 case MESSAGE_DISCONNECT: /* port is disconnected */
2664                 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);
2665                 port_disconnect_release(portlist, message_type, param);
2666                 break;
2667
2668                 /* PORT sends a RELEASE message */
2669                 case MESSAGE_RELEASE: /* port releases */
2670                 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);
2671                 /* portlist is release at port_disconnect_release, thanx Paul */
2672                 port_disconnect_release(portlist, message_type, param);
2673                 break;
2674
2675                 /* PORT sends a TIMEOUT message */
2676                 case MESSAGE_TIMEOUT:
2677                 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);
2678                 port_timeout(portlist, message_type, param);
2679                 break; /* release */
2680
2681                 /* PORT sends a NOTIFY message */
2682                 case MESSAGE_NOTIFY:
2683                 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);
2684                 port_notify(portlist, message_type, param);
2685                 break;
2686
2687                 /* PORT sends a PROGRESS message */
2688                 case MESSAGE_PROGRESS:
2689                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received progress.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2690                 port_progress(portlist, message_type, param);
2691                 break;
2692
2693                 /* PORT sends a SUSPEND message */
2694                 case MESSAGE_SUSPEND:
2695                 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);
2696                 port_suspend(portlist, message_type, param);
2697                 break; /* suspend */
2698
2699                 /* PORT sends a RESUME message */
2700                 case MESSAGE_RESUME:
2701                 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);
2702                 port_resume(portlist, message_type, param);
2703                 break;
2704
2705 #if 0
2706                 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2707                 /* port assigns bchannel */
2708                 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2709                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel message %d from port.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type);
2710                 /* only one port is expected to be connected to bchannel */
2711                 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2712                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2713                 break;
2714 #endif
2715
2716
2717                 default:
2718                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: %d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
2719         }
2720
2721         /* Note: this endpoint may be destroyed, so we MUST return */
2722 }
2723
2724
2725 /* messages from join
2726  */
2727 /* join MESSAGE_CRYPT */
2728 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2729 {
2730         switch(param->crypt.type) {
2731                 /* message from remote port to "crypt manager" */
2732                 case CU_ACTK_REQ:           /* activate key-exchange */
2733                 case CU_ACTS_REQ:            /* activate shared key */
2734                 case CU_DACT_REQ:          /* deactivate */
2735                 case CU_INFO_REQ:         /* request last info message */
2736                 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2737                 break;
2738
2739                 /* message from "crypt manager" to user */
2740                 case CU_ACTK_CONF:          /* key-echange done */
2741                 case CU_ACTS_CONF:          /* shared key done */
2742                 case CU_DACT_CONF:           /* deactivated */
2743                 case CU_DACT_IND:           /* deactivated */
2744                 case CU_ERROR_IND:         /* receive error message */
2745                 case CU_INFO_IND:         /* receive info message */
2746                 case CU_INFO_CONF:         /* receive info message */
2747                 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2748                 break;
2749
2750                 default:
2751                 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);
2752         }
2753 }
2754
2755 /* join MESSAGE_INFORMATION */
2756 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2757 {
2758         struct lcr_msg *message;
2759
2760         e_overlap = 1;
2761
2762         while(portlist) {
2763                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2764                 memcpy(&message->param.information, &param->information, sizeof(struct dialing_info));
2765                 message_put(message);
2766                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2767                 portlist = portlist->next;
2768         }
2769 }
2770
2771 /* join MESSAGE_FACILITY */
2772 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2773 {
2774         struct lcr_msg *message;
2775
2776         if (!e_ext.facility && e_ext.number[0]) {
2777                 return;
2778         }
2779
2780         while(portlist) {
2781                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2782                 memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2783                 message_put(message);
2784                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2785                 portlist = portlist->next;
2786         }
2787 }
2788
2789 /* join MESSAGE_MORE */
2790 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2791 {
2792         struct lcr_msg *message;
2793
2794         new_state(EPOINT_STATE_IN_OVERLAP);
2795         
2796         /* own dialtone */
2797         if (e_join_pattern && e_ext.own_setup) {
2798                 /* disconnect audio */
2799                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2800                 message->param.audiopath = 0;
2801                 message_put(message);
2802         }
2803         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2804                         if (e_dialinginfo.id[0])
2805                                 set_tone(portlist, "dialing");
2806                         else
2807                                 set_tone(portlist, "dialtone");
2808                         return;
2809         }
2810         if (e_dialinginfo.id[0]) {
2811                 set_tone(portlist, "dialing");
2812         } else {
2813                 if (e_ext.number[0])
2814                         set_tone(portlist, "dialpbx");
2815                 else
2816                         set_tone(portlist, "dialtone");
2817         }
2818 }
2819
2820 /* join MESSAGE_PROCEEDING */
2821 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2822 {
2823         struct lcr_msg *message;
2824
2825         new_state(EPOINT_STATE_IN_PROCEEDING);
2826
2827         /* own proceeding tone */
2828         if (e_join_pattern) {
2829                 /* connect / disconnect audio */
2830                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2831                 if (e_ext.own_proceeding)
2832                         message->param.audiopath = 0;
2833                 else
2834                         message->param.audiopath = 1;
2835                 message_put(message);
2836         }
2837 //                      UCPY(e_join_tone, "proceeding");
2838         if (portlist) {
2839                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2840                 message_put(message);
2841                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2842         }
2843         set_tone(portlist, "proceeding");
2844 }
2845
2846 /* join MESSAGE_ALERTING */
2847 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2848 {
2849         struct lcr_msg *message;
2850
2851         new_state(EPOINT_STATE_IN_ALERTING);
2852
2853         /* own alerting tone */
2854         if (e_join_pattern) {
2855                 /* connect / disconnect audio */
2856                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2857                 if (e_ext.own_alerting)
2858                         message->param.audiopath = 0;
2859                 else
2860                         message->param.audiopath = 1;
2861                 message_put(message);
2862         }
2863         if (portlist) {
2864                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2865                 message_put(message);
2866                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2867         }
2868         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2869                 set_tone(portlist, "ringing");
2870                 return;
2871         }
2872         if (e_ext.number[0])
2873                 set_tone(portlist, "ringpbx");
2874         else
2875                 set_tone(portlist, "ringing");
2876
2877         if (e_ext.number[0])
2878                 e_dtmf = 1; /* allow dtmf */
2879 }
2880
2881 /* join MESSAGE_CONNECT */
2882 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2883 {
2884         struct lcr_msg *message;
2885         time_t now;
2886
2887         new_state(EPOINT_STATE_CONNECT);
2888 //                      UCPY(e_join_tone, "");
2889 //                      
2890         if (e_ext.number[0])
2891                 e_dtmf = 1; /* allow dtmf */
2892
2893         e_powerdial_on = 0;
2894         unsched_timer(&e_powerdial_timeout);
2895         memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_callerinfo));
2896         if(portlist) {
2897                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2898                 memcpy(&message->param, param, sizeof(union parameter));
2899
2900                 /* screen clip if prefix is required */
2901                 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2902                         SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2903                         SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2904                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2905                 }
2906
2907                 /* use internal caller id */
2908                 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2909                         SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2910                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2911                 }
2912
2913                 /* handle restricted caller ids */
2914                 apply_callerid_restriction(&e_ext, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
2915                 /* display callerid if desired for extension */
2916                 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));
2917
2918                 /* use conp, if enabld */
2919 //              if (!e_ext.centrex)
2920 //                      message->param.connectinfo.name[0] = '\0';
2921
2922                 /* send connect */
2923                 message_put(message);
2924                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2925         }
2926         set_tone(portlist, NULL);
2927         e_join_pattern = 0;
2928         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2929         message->param.audiopath = 1;
2930         message_put(message);
2931         time(&now);
2932         e_start = now;
2933 }
2934
2935 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2936 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2937 {
2938         char cause[16];
2939         struct lcr_msg *message;
2940         struct port_list *portlist = NULL;
2941         time_t now;
2942
2943
2944         /* be sure that we are active */
2945         notify_active();
2946         e_tx_state = NOTIFY_STATE_ACTIVE;
2947
2948         /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2949         if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2950                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2951
2952                 /* set time for power dialing */
2953                 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2954                 e_powercount++;
2955
2956                 /* set redial tone */
2957                 if (ea_endpoint->ep_portlist) {
2958                         e_join_pattern = 0;
2959                 }
2960                 set_tone(ea_endpoint->ep_portlist, "redial");
2961                 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);
2962                 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2963                 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2964                         new_state(EPOINT_STATE_IN_PROCEEDING);
2965                         if (ea_endpoint->ep_portlist) {
2966                                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2967                                 message_put(message);
2968                                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2969                         }
2970 /* caused the error, that the first knock sound was not there */
2971 /*                                      set_tone(portlist, "proceeding"); */
2972                 }
2973                 /* send display of powerdialing */
2974                 if (e_ext.display_dialing) {
2975                         portlist = ea_endpoint->ep_portlist;
2976                         while (portlist) {
2977                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2978                                 if (e_powerlimit)
2979                                         SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2980                                 else
2981                                         SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2982                                 message_put(message);
2983                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2984                                 portlist = portlist->next;
2985                         }
2986                 }
2987                 return;
2988         }
2989
2990         /* set stop time */
2991         time(&now);
2992         e_stop = now;
2993
2994         if ((e_state!=EPOINT_STATE_CONNECT
2995           && e_state!=EPOINT_STATE_OUT_DISCONNECT
2996           && e_state!=EPOINT_STATE_IN_OVERLAP
2997           && e_state!=EPOINT_STATE_IN_PROCEEDING
2998           && e_state!=EPOINT_STATE_IN_ALERTING)
2999          || !ea_endpoint->ep_portlist) { /* or no port */
3000                 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3001                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3002                 return; /* must exit here */
3003         }
3004         /* save cause */
3005         if (!e_join_cause) {
3006                 e_join_cause = param->disconnectinfo.cause;
3007                 e_join_location = param->disconnectinfo.location;
3008         }
3009
3010         /* on release we need the audio again! */
3011         if (message_type == MESSAGE_RELEASE) {
3012                 e_join_pattern = 0;
3013                 ea_endpoint->ep_join_id = 0;
3014         }
3015         /* disconnect and select tone */
3016         new_state(EPOINT_STATE_OUT_DISCONNECT);
3017         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3018         /* if own_cause, we must release the join */
3019         if (e_ext.own_cause /* own cause */
3020          || !e_join_pattern) { /* no patterns */
3021                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have own cause or we have no patterns. (own_cause=%d pattern=%d)\n", ea_endpoint->ep_serial, e_ext.own_cause, e_join_pattern);
3022                 if (message_type != MESSAGE_RELEASE)
3023                         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3024                 e_join_pattern = 0;
3025         } else { /* else we enable audio */
3026                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3027                 message->param.audiopath = 1;
3028                 message_put(message);
3029         }
3030         /* send disconnect message */
3031         SCPY(e_tone, cause);
3032         portlist = ea_endpoint->ep_portlist;
3033         while(portlist) {
3034                 set_tone(portlist, cause);
3035                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3036                 portlist = portlist->next;
3037         }
3038 }
3039
3040 /* join MESSAGE_SETUP */
3041 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3042 {
3043         struct lcr_msg *message;
3044 //      struct interface        *interface;
3045
3046         /* if we already in setup state, we just update the dialing with new digits */
3047         if (e_state == EPOINT_STATE_OUT_SETUP
3048          || e_state == EPOINT_STATE_OUT_OVERLAP) {
3049                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3050                 /* if digits changed, what we have already dialed */
3051                 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3052                         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);
3053                         /* release all ports */
3054                         while((portlist = ea_endpoint->ep_portlist)) {
3055                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3056                                 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3057                                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3058                                 message_put(message);
3059                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3060                                 ea_endpoint->free_portlist(portlist);
3061                         }
3062
3063                         /* disconnect audio */
3064                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3065                         message->param.audiopath = 0;
3066                         message_put(message);
3067
3068                         /* get dialing info */
3069                         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3070                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3071                         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3072                         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3073                         new_state(EPOINT_STATE_OUT_OVERLAP);
3074
3075                         /* get time */
3076                         schedule_timer(&e_redial_timeout, 1, 0);
3077                         return;
3078                 }
3079                 /* if we have a pending redial, so we just adjust the dialing number */
3080                 if (e_redial_timeout.active) {
3081                         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);
3082                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3083                         return;
3084                 }
3085                 if (!ea_endpoint->ep_portlist) {
3086                         PERROR("ERROR: overlap dialing to a NULL port relation\n");
3087                 }
3088                 if (ea_endpoint->ep_portlist->next) {
3089                         PERROR("ERROR: overlap dialing to a port_list port relation\n");
3090                 }
3091                 if (e_state == EPOINT_STATE_OUT_SETUP) {
3092                         /* queue digits */
3093                         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);
3094                         SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3095                         
3096                 } else {
3097                         /* get what we have not dialed yet */
3098                         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));
3099                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3100                         SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3101                         message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3102                         message_put(message);
3103                         logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3104                 }
3105                 /* always store what we have dialed or queued */
3106                 memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3107                 
3108                 return;
3109         }
3110         if (e_state != EPOINT_STATE_IDLE) {
3111                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3112                 return;
3113         }
3114         /* if an internal extension is dialed, copy that number */
3115         if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3116                 SCPY(e_ext.number, param->setup.dialinginfo.id);
3117         /* if an internal extension is dialed, get extension's info about caller */
3118         if (e_ext.number[0]) {
3119                 if (!read_extension(&e_ext, e_ext.number)) {
3120                         e_ext.number[0] = '\0';
3121                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3122                 }
3123         }
3124
3125         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3126         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3127         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3128         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3129
3130         /* process (voice over) data calls */
3131         if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3132                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3133                 memset(&e_capainfo, 0, sizeof(e_capainfo));
3134                 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3135                 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3136                 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3137         }
3138
3139         new_state(EPOINT_STATE_OUT_SETUP);
3140         /* call special setup routine */
3141         out_setup();
3142 }
3143
3144 /* join MESSAGE_mISDNSIGNAL */
3145 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3146 {
3147         struct lcr_msg *message;
3148
3149         while(portlist) {
3150                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3151                 memcpy(&message->param, param, sizeof(union parameter));
3152                 message_put(message);
3153                 portlist = portlist->next;
3154         }
3155 }
3156
3157 /* join MESSAGE_NOTIFY */
3158 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3159 {
3160         struct lcr_msg *message;
3161         int new_state;
3162
3163         if (param->notifyinfo.notify) {
3164                 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3165 //              /* if notification was generated locally, we turn hold music on/off */ 
3166 //              if (param->notifyinfo.local)
3167 // 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)
3168                 {
3169                         if (e_hold) {
3170                                 /* unhold if */
3171                                 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3172                                         if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3173                                                 while(portlist) {
3174                                                         set_tone(portlist, "");
3175                                                         portlist = portlist->next;
3176                                                 }
3177                                         }
3178                                         portlist = ea_endpoint->ep_portlist;
3179                                         e_hold = 0;
3180                                 }
3181                         } else {
3182                                 /* hold if */
3183                                 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3184                                         while(portlist) {
3185                                                 set_tone(portlist, "hold");
3186                                                 portlist = portlist->next;
3187                                         }
3188                                         portlist = ea_endpoint->ep_portlist;
3189                                         e_hold = 1;
3190                                 }
3191                         }
3192                 }
3193                 /* save new state */
3194                 e_tx_state = new_state;
3195         }
3196
3197         /* notify port(s) about it */
3198         while(portlist) {
3199                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3200                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
3201                 /* handle restricted caller ids */
3202                 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3203                 /* display callerid if desired for extension */
3204                 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));
3205                 message_put(message);
3206                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3207                 portlist = portlist->next;
3208         }
3209 }
3210
3211 /* JOIN sends messages to the endpoint
3212  */
3213 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3214 {
3215         struct port_list *portlist;
3216         struct lcr_msg *message;
3217
3218         if (!join_id) {
3219                 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3220                 return;
3221         }
3222
3223         portlist = ea_endpoint->ep_portlist;
3224
3225         /* send MESSAGE_DATA to port */
3226         if (message_type == MESSAGE_DATA) {
3227                 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3228                         /* skip if no port relation */
3229                         if (!portlist)
3230                                 return;
3231                         /* skip if more than one port relation */
3232                         if (portlist->next)
3233                                 return;
3234                         /* forward audio data to port */
3235                         message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3236                         return;
3237                 }
3238         }
3239
3240 //      PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received message %d for active JOIN (terminal %s, caller id %s state=%d)\n", ea_endpoint->ep_serial, message, e_ext.number, e_callerinfo.id, e_state);
3241         switch(message_type) {
3242                 /* JOIN SENDS TONE message */
3243                 case MESSAGE_TONE:
3244                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received tone message: '%d'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->tone.name);
3245                 set_tone(portlist, param->tone.name);
3246                 break;
3247
3248                 /* JOIN SENDS CRYPT message */
3249                 case MESSAGE_CRYPT:
3250                 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);
3251                 join_crypt(portlist, message_type, param);
3252                 break;
3253
3254                 /* JOIN sends INFORMATION message */
3255                 case MESSAGE_INFORMATION:
3256                 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);
3257                 join_information(portlist, message_type, param);
3258                 break;
3259
3260                 /* JOIN sends FACILITY message */
3261                 case MESSAGE_FACILITY:
3262                 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);
3263                 join_facility(portlist, message_type, param);
3264                 break;
3265
3266                 /* JOIN sends OVERLAP message */
3267                 case MESSAGE_OVERLAP:
3268                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received 'more info required'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3269                 if (e_state!=EPOINT_STATE_IN_SETUP
3270                  && e_state!=EPOINT_STATE_IN_OVERLAP) {
3271                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3272                         break;
3273                 }
3274                 join_overlap(portlist, message_type, param);
3275                 break;
3276
3277                 /* JOIN sends PROCEEDING message */
3278                 case MESSAGE_PROCEEDING:
3279                 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);
3280                 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3281                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3282                         break;
3283                 }
3284                 join_proceeding(portlist, message_type, param);
3285                 break;
3286
3287                 /* JOIN sends ALERTING message */
3288                 case MESSAGE_ALERTING:
3289                 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);
3290                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3291                  && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3292                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3293                         break;
3294                 }
3295                 join_alerting(portlist, message_type, param);
3296                 break;
3297
3298                 /* JOIN sends CONNECT message */
3299                 case MESSAGE_CONNECT:
3300                 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);
3301                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3302                  && e_state!=EPOINT_STATE_IN_PROCEEDING
3303                  && e_state!=EPOINT_STATE_IN_ALERTING) {
3304                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3305                         break;
3306                 }
3307                 join_connect(portlist, message_type, param);
3308                 break;
3309
3310                 /* JOIN sends DISCONNECT/RELEASE message */
3311                 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3312                 case MESSAGE_RELEASE: /* JOIN releases */
3313                 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);
3314                 join_disconnect_release(message_type, param);
3315                 break;
3316
3317                 /* JOIN sends SETUP message */
3318                 case MESSAGE_SETUP:
3319                 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);
3320                 join_setup(portlist, message_type, param);
3321                 break;
3322
3323                 /* JOIN sends special mISDNSIGNAL message */
3324                 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3325                 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);
3326                 join_mISDNsignal(portlist, message_type, param);
3327                 break;
3328
3329 #if 0
3330                 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3331                 /* JOIN requests bchannel */
3332                 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3333                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel assignment %d from join.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type);
3334                 /* only one port is expected to be connected to bchannel */
3335                 if (!portlist)
3336                         break;
3337                 if (portlist->next)
3338                         break;
3339                 e_join_pattern = 1;
3340                 SCPY(e_tone, "");
3341                 set_tone(portlist, NULL);
3342                 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3343                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3344                 break;
3345 #endif
3346
3347                 /* JOIN has pattern available */
3348                 case MESSAGE_PATTERN: /* indicating pattern available */
3349                 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);
3350                 if (!e_join_pattern) {
3351                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3352                         e_join_pattern = 1;
3353                         SCPY(e_tone, "");
3354                         while(portlist) {
3355                                 set_tone(portlist, NULL);
3356                                 portlist = portlist->next;
3357                         }
3358                         /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3359                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3360                         message->param.audiopath = 1;
3361                         message_put(message);
3362                 }
3363                 break;
3364
3365                 /* JOIN has no pattern available */
3366                 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3367                 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);
3368                 if (e_join_pattern) {
3369                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3370                         e_join_pattern = 0;
3371                         /* disconnect our audio tx and rx */
3372                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3373                         message->param.audiopath = 0;
3374                         message_put(message);
3375                 }
3376                 break;
3377
3378 #if 0
3379                 /* JOIN (dunno at the moment) */
3380                 case MESSAGE_REMOTE_AUDIO:
3381                 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);
3382                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3383                 message->param.audiopath = param->channel;
3384                 message_put(message);
3385                 break;
3386 #endif
3387
3388                 /* JOIN sends a notify message */
3389                 case MESSAGE_NOTIFY:
3390                 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);
3391                 join_notify(portlist, message_type, param);
3392                 break;
3393
3394                 /* JOIN wants keypad / dtmf */
3395                 case MESSAGE_ENABLEKEYPAD:
3396                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received keypad enable request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3397                 e_enablekeypad = 1;
3398                 e_dtmf = 1;
3399                 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3400                 end_trace();
3401                 break;
3402
3403                 default:
3404                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: #%d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
3405         }
3406 }
3407
3408
3409 /* pick_join will connect the first incoming call found. the endpoint
3410  * will receivce a MESSAGE_CONNECT.
3411  */
3412 int match_list(char *list, char *item)
3413 {
3414         char *end, *next = NULL;
3415
3416         /* no list make matching */
3417         if (!list)
3418                 return(1);
3419
3420         while(42) {
3421                 /* eliminate white spaces */
3422                 while (*list <= ' ')
3423                         list++;
3424                 if (*list == ',') {
3425                         list++;
3426                         continue;
3427                 }
3428                 /* if end of list is reached, we return */
3429                 if (list[0] == '\0')
3430                         return(0);
3431                 /* if we have more than one entry (left) */
3432                 if ((end = strchr(list, ',')))
3433                         next = end + 1;
3434                 else
3435                         next = end = strchr(list, '\0');
3436                 while (*(end-1) <= ' ')
3437                         end--;
3438                 /* if string part matches item */
3439                 if (!strncmp(list, item, end-list))
3440                         return(1);
3441                 list = next;
3442         }
3443 }
3444
3445 void EndpointAppPBX::pick_join(char *extensions)
3446 {
3447         struct lcr_msg *message;
3448         struct port_list *portlist;
3449         class Port *port;
3450         class EndpointAppPBX *eapp, *found;
3451         class Join *join;
3452         class JoinPBX *joinpbx;
3453         struct join_relation *relation;
3454         int vbox;
3455
3456         /* find an endpoint that is ringing internally or vbox with higher priority */
3457         vbox = 0;
3458         found = NULL;
3459         eapp = apppbx_first;
3460         while(eapp) {
3461                 if (eapp!=this && ea_endpoint->ep_portlist) {
3462                         portlist = eapp->ea_endpoint->ep_portlist;
3463                         while(portlist) {
3464                                 if ((port = find_port_id(portlist->port_id))) {
3465                                         if (port->p_type == PORT_TYPE_VBOX_OUT) {
3466                                                 if (match_list(extensions, eapp->e_ext.number)) {
3467                                                         found = eapp;
3468                                                         vbox = 1;
3469                                                         break;
3470                                                 }
3471                                         }
3472                                         if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3473                                          && port->p_state==PORT_STATE_OUT_ALERTING)
3474                                                 if (match_list(extensions, eapp->e_ext.number)) {
3475                                                         found = eapp;
3476                                                 }
3477                                 }
3478                                 portlist = portlist->next;
3479                         }
3480                         if (portlist)
3481                                 break;
3482                 }
3483                 eapp = eapp->next;
3484         }
3485
3486         /* if no endpoint found */
3487         if (!found) {
3488                 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);
3489 reject:
3490                 set_tone(ea_endpoint->ep_portlist, "cause_10");
3491                 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3492                 new_state(EPOINT_STATE_OUT_DISCONNECT);
3493                 return;
3494         }
3495         eapp = found;
3496
3497         if (ea_endpoint->ep_join_id) {
3498                 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3499                 goto reject;
3500         }
3501         if (!eapp->ea_endpoint->ep_join_id) {
3502                 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3503                 goto reject;
3504         }
3505         join = find_join_id(eapp->ea_endpoint->ep_join_id);
3506         if (!join) {
3507                 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3508                 goto reject;
3509         }
3510         if (join->j_type != JOIN_TYPE_PBX) {
3511                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3512                 goto reject;
3513         }
3514         joinpbx = (class JoinPBX *)join;
3515         relation = joinpbx->j_relation;
3516         if (!relation) {
3517                 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3518                 goto reject;
3519         }
3520         while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3521                 relation = relation->next;
3522                 if (!relation) {
3523                         PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3524                         goto reject;
3525                 }
3526         }
3527
3528         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3529
3530         if (options.deb & DEBUG_EPOINT) {
3531                 class Join *debug_c = join_first;
3532                 class Endpoint *debug_e = epoint_first;
3533                 class Port *debug_p = port_first;
3534
3535                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3536
3537                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3538                 while(debug_c) {
3539                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3540                         debug_c = debug_c->next;
3541                 }
3542                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3543                 while(debug_e) {
3544                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3545                         debug_e = debug_e->next;
3546                 }
3547                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3548                 while(debug_p) {
3549                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3550                         debug_p = debug_p->next;
3551                 }
3552         }
3553
3554         /* relink join */
3555         ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3556         relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3557         eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3558
3559         /* connnecting our endpoint */
3560         new_state(EPOINT_STATE_CONNECT);
3561         if (e_ext.number[0])
3562                 e_dtmf = 1;
3563         set_tone(ea_endpoint->ep_portlist, NULL);
3564
3565         /* now we send a release to the ringing endpoint */
3566         message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3567         message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3568         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3569         message_put(message);
3570
3571         /* we send a connect to the join with our caller id */
3572         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3573         SCPY(message->param.connectinfo.id, e_callerinfo.id);
3574         message->param.connectinfo.present = e_callerinfo.present;
3575         message->param.connectinfo.screen = e_callerinfo.screen;
3576         message->param.connectinfo.itype = e_callerinfo.itype;
3577         message->param.connectinfo.ntype = e_callerinfo.ntype;
3578         message_put(message);
3579
3580         /* we send a connect to our port with the remote callerid */
3581         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3582         SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3583         message->param.connectinfo.present = eapp->e_callerinfo.present;
3584         message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3585         message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3586         message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3587         /* handle restricted caller ids */
3588         apply_callerid_restriction(&e_ext, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
3589         /* display callerid if desired for extension */
3590         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));
3591         message_put(message);
3592
3593         /* we send a connect to the audio path (not for vbox) */
3594         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3595         message->param.audiopath = 1;
3596         message_put(message);
3597
3598         /* beeing paranoid, we make call update */
3599         trigger_work(&joinpbx->j_updatebridge);
3600
3601         if (options.deb & DEBUG_EPOINT) {
3602                 class Join *debug_c = join_first;
3603                 class Endpoint *debug_e = epoint_first;
3604                 class Port *debug_p = port_first;
3605
3606                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3607
3608                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3609                 while(debug_c) {
3610                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3611                         debug_c = debug_c->next;
3612                 }
3613                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3614                 while(debug_e) {
3615                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3616                         debug_e = debug_e->next;
3617                 }
3618                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3619                 while(debug_p) {
3620                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3621                         debug_p = debug_p->next;
3622                 }
3623         }
3624 }
3625
3626
3627 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3628  */
3629 void EndpointAppPBX::join_join(void)
3630 {
3631         struct lcr_msg *message;
3632         struct join_relation *our_relation, *other_relation;
3633         struct join_relation **our_relation_pointer, **other_relation_pointer;
3634         class Join *our_join, *other_join;
3635         class JoinPBX *our_joinpbx, *other_joinpbx;
3636         class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3637         class Port *our_port, *other_port;
3638         class Pdss1 *our_pdss1, *other_pdss1;
3639
3640         /* are we a candidate to join a join? */
3641         our_join = find_join_id(ea_endpoint->ep_join_id);
3642         if (!our_join) {
3643                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3644                 return;
3645         }
3646         if (our_join->j_type != JOIN_TYPE_PBX) {
3647                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3648                 return;
3649         }
3650         our_joinpbx = (class JoinPBX *)our_join;
3651         if (!ea_endpoint->ep_portlist) {
3652                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3653                 return;
3654         }
3655         if (!e_ext.number[0]) {
3656                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3657                 return;
3658         }
3659         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3660         if (!our_port) {
3661                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3662                 return;
3663         }
3664         if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3665                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3666                 return;
3667         }
3668         our_pdss1 = (class Pdss1 *)our_port;
3669
3670         /* find an endpoint that is on hold and has the same mISDNport that we are on */
3671         other_eapp = apppbx_first;
3672         while(other_eapp) {
3673                 if (other_eapp == this) {
3674                         other_eapp = other_eapp->next;
3675                         continue;
3676                 }
3677                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint candiate: (ep%d) terminal='%s' port=%s join=%d.\n", ea_endpoint->ep_serial, other_eapp->ea_endpoint->ep_serial, other_eapp->e_ext.number, (other_eapp->ea_endpoint->ep_portlist)?"YES":"NO", other_eapp->ea_endpoint->ep_join_id);
3678                 if (other_eapp->e_ext.number[0] /* has terminal */
3679                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3680                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3681                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3682                         if (other_port) { /* port still exists */
3683                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3684                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3685                                         other_pdss1 = (class Pdss1 *)other_port;
3686                                         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);
3687                                         if (other_pdss1->p_m_hold /* port is on hold */
3688                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3689                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3690                                                 break;
3691                                 } else {
3692                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3693                                 }
3694                         } else {
3695                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3696                         }
3697                 }
3698                 other_eapp = other_eapp->next;
3699         }
3700         if (!other_eapp) {
3701                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3702                 return;
3703         }
3704         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3705
3706         /* if we have the same join */
3707         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3708                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3709                 return;
3710         }
3711         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3712         if (!other_join) {
3713                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3714                 return;
3715         }
3716         if (other_join->j_type != JOIN_TYPE_PBX) {
3717                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3718                 return;
3719         }
3720         other_joinpbx = (class JoinPBX *)other_join;
3721         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3722                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3723                 return;
3724         }
3725
3726         /* remove relation to endpoint for join on hold */
3727         other_relation = other_joinpbx->j_relation;
3728         other_relation_pointer = &other_joinpbx->j_relation;
3729         while(other_relation) {
3730                 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3731                         /* detach other endpoint on hold */
3732                         *other_relation_pointer = other_relation->next;
3733                         FREE(other_relation, sizeof(struct join_relation));
3734                         cmemuse--;
3735                         other_relation = *other_relation_pointer;
3736                         other_eapp->ea_endpoint->ep_join_id = 0;
3737                         continue;
3738                 }
3739
3740                 /* change join/hold pointer of endpoint to the new join */
3741                 temp_epoint = find_epoint_id(other_relation->epoint_id);
3742                 if (temp_epoint) {
3743                         if (temp_epoint->ep_join_id == other_join->j_serial)
3744                                 temp_epoint->ep_join_id = our_join->j_serial;
3745                 }
3746
3747                 other_relation_pointer = &other_relation->next;
3748                 other_relation = other_relation->next;
3749         }
3750         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3751
3752         /* join call relations */
3753         our_relation = our_joinpbx->j_relation;
3754         our_relation_pointer = &our_joinpbx->j_relation;
3755         while(our_relation) {
3756                 our_relation_pointer = &our_relation->next;
3757                 our_relation = our_relation->next;
3758         }
3759         *our_relation_pointer = other_joinpbx->j_relation;
3760         other_joinpbx->j_relation = NULL;
3761         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3762
3763         /* release endpoint on hold */
3764         message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3765         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3766         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3767         message_put(message);
3768         
3769         /* if we are not a partyline, we get partyline state from other join */
3770         our_joinpbx->j_partyline += other_joinpbx->j_partyline; 
3771
3772         /* remove empty join */
3773         delete other_join;
3774         PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3775
3776         /* mixer must update */
3777         trigger_work(&our_joinpbx->j_updatebridge);
3778
3779         /* we send a retrieve to that endpoint */
3780         // mixer will update the hold-state of the join and send it to the endpoints is changes
3781 }
3782
3783
3784 /* check if we have an external call
3785  * this is used to check for encryption ability
3786  */
3787 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3788 {
3789         struct join_relation *relation;
3790         class Join *join;
3791         class JoinPBX *joinpbx;
3792         class Endpoint *epoint;
3793
3794         /* some paranoia check */
3795         if (!ea_endpoint->ep_portlist) {
3796                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3797                 *errstr = "No Call";
3798                 return(1);
3799         }
3800         if (!e_ext.number[0]) {
3801                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3802                 *errstr = "No Call";
3803                 return(1);
3804         }
3805
3806         /* check if we have a join with 2 parties */
3807         join = find_join_id(ea_endpoint->ep_join_id);
3808         if (!join) {
3809                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3810                 *errstr = "No Call";
3811                 return(1);
3812         }
3813         if (join->j_type != JOIN_TYPE_PBX) {
3814                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3815                 *errstr = "No PBX Call";
3816                 return(1);
3817         }
3818         joinpbx = (class JoinPBX *)join;
3819         relation = joinpbx->j_relation;
3820         if (!relation) {
3821                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3822                 *errstr = "No Call";
3823                 return(1);
3824         }
3825         if (!relation->next) {
3826                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3827                 *errstr = "No Call";
3828                 return(1);
3829         }
3830         if (relation->next->next) {
3831                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3832                 *errstr = "Err: Conference";
3833                 return(1);
3834         }
3835         if (relation->epoint_id == ea_endpoint->ep_serial) {
3836                 relation = relation->next;
3837                 if (relation->epoint_id == ea_endpoint->ep_serial) {
3838                         PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3839                         *errstr = "Software Error";
3840                         return(1);
3841                 }
3842         }
3843
3844         /* check remote port for external call */
3845         epoint = find_epoint_id(relation->epoint_id);
3846         if (!epoint) {
3847                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3848                 *errstr = "No Call";
3849                 return(1);
3850         }
3851         if (!epoint->ep_portlist) {
3852                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3853                 *errstr = "No Call";
3854                 return(1);
3855         }
3856         *port = find_port_id(epoint->ep_portlist->port_id);
3857         if (!(*port)) {
3858                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3859                 *errstr = "No Call";
3860                 return(1);
3861         }
3862         if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3863                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3864                 *errstr = "No Ext Call";
3865                 return(1);
3866         }
3867         if ((*port)->p_state != PORT_STATE_CONNECT) {
3868                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3869                 *errstr = "No Ext Connect";
3870                 return(1);
3871         }
3872         return(0);
3873 }
3874
3875 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3876 {
3877         const char *logtext = "unknown";
3878         char buffer[64];
3879
3880         switch(message_type) {
3881                 case MESSAGE_SETUP:
3882                 trace_header("SETUP", dir);
3883                 if (dir == DIRECTION_OUT)
3884                         add_trace("to", NULL, "CH(%lu)", port_id);
3885                 if (dir == DIRECTION_IN)
3886                         add_trace("from", NULL, "CH(%lu)", port_id);
3887                 if (param->setup.callerinfo.extension[0])
3888                         add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3889                 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3890                 switch(param->setup.callerinfo.present) {
3891                         case INFO_PRESENT_RESTRICTED:
3892                         add_trace("caller id", "present", "restricted");
3893                         break;
3894                         case INFO_PRESENT_ALLOWED:
3895                         add_trace("caller id", "present", "allowed");
3896                         break;
3897                         default:
3898                         add_trace("caller id", "present", "not available");
3899                 }
3900                 if (param->setup.callerinfo.ntype2) {
3901                         add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3902                         switch(param->setup.callerinfo.present) {
3903                                 case INFO_PRESENT_RESTRICTED:
3904                                 add_trace("caller id2", "present", "restricted");
3905                                 break;
3906                                 case INFO_PRESENT_ALLOWED:
3907                                 add_trace("caller id2", "present", "allowed");
3908                                 break;
3909                                 default:
3910                                 add_trace("caller id2", "present", "not available");
3911                         }
3912                 }
3913                 if (param->setup.redirinfo.id[0]) {
3914                         add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3915                         switch(param->setup.redirinfo.present) {
3916                                 case INFO_PRESENT_RESTRICTED:
3917                                 add_trace("redir'ing", "present", "restricted");
3918                                 break;
3919                                 case INFO_PRESENT_ALLOWED:
3920                                 add_trace("redir'ing", "present", "allowed");
3921                                 break;
3922                                 default:
3923                                 add_trace("redir'ing", "present", "not available");
3924                         }
3925                 }
3926                 if (param->setup.dialinginfo.id[0])
3927                         add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3928                 if (param->setup.dialinginfo.keypad[0])
3929                         add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3930                 if (param->setup.dialinginfo.display[0])
3931                         add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3932                 if (param->setup.dialinginfo.sending_complete)
3933                         add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3934                 end_trace();
3935                 break;
3936
3937                 case MESSAGE_OVERLAP:
3938                 trace_header("SETUP ACKNOWLEDGE", dir);
3939                 if (dir == DIRECTION_OUT)
3940                         add_trace("to", NULL, "CH(%lu)", port_id);
3941                 if (dir == DIRECTION_IN)
3942                         add_trace("from", NULL, "CH(%lu)", port_id);
3943                 end_trace();
3944                 break;
3945
3946                 case MESSAGE_PROCEEDING:
3947                 trace_header("PROCEEDING", dir);
3948                 if (dir == DIRECTION_OUT)
3949                         add_trace("to", NULL, "CH(%lu)", port_id);
3950                 if (dir == DIRECTION_IN)
3951                         add_trace("from", NULL, "CH(%lu)", port_id);
3952                 end_trace();
3953                 break;
3954
3955                 case MESSAGE_ALERTING:
3956                 trace_header("ALERTING", dir);
3957                 if (dir == DIRECTION_OUT)
3958                         add_trace("to", NULL, "CH(%lu)", port_id);
3959                 if (dir == DIRECTION_IN)
3960                         add_trace("from", NULL, "CH(%lu)", port_id);
3961                 end_trace();
3962                 break;
3963
3964                 case MESSAGE_CONNECT:
3965                 trace_header("CONNECT", dir);
3966                 if (dir == DIRECTION_OUT)
3967                         add_trace("to", NULL, "CH(%lu)", port_id);
3968                 if (dir == DIRECTION_IN)
3969                         add_trace("from", NULL, "CH(%lu)", port_id);
3970                 if (param->connectinfo.extension[0])
3971                         add_trace("extension", NULL, "%s", param->connectinfo.extension);
3972                 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3973                 switch(param->connectinfo.present) {
3974                         case INFO_PRESENT_RESTRICTED:
3975                         add_trace("connect id", "present", "restricted");
3976                         break;
3977                         case INFO_PRESENT_ALLOWED:
3978                         add_trace("connect id", "present", "allowed");
3979                         break;
3980                         default:
3981                         add_trace("connect id", "present", "not available");
3982                 }
3983                 if (param->connectinfo.display[0])
3984                         add_trace("display", NULL, "%s", param->connectinfo.display);
3985                 end_trace();
3986                 break;
3987
3988                 case MESSAGE_DISCONNECT:
3989                 case MESSAGE_RELEASE:
3990                 if (message_type == MESSAGE_DISCONNECT)
3991                         trace_header("DISCONNECT", dir);
3992                 else
3993                         trace_header("RELEASE", dir);
3994                 if (dir == DIRECTION_OUT)
3995                         add_trace("to", NULL, "CH(%lu)", port_id);
3996                 if (dir == DIRECTION_IN)
3997                         add_trace("from", NULL, "CH(%lu)", port_id);
3998                 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3999                 switch(param->disconnectinfo.location) {
4000                         case LOCATION_USER:
4001                         add_trace("cause", "location", "0-User");
4002                         break;
4003                         case LOCATION_PRIVATE_LOCAL:
4004                         add_trace("cause", "location", "1-Local-PBX");
4005                         break;
4006                         case LOCATION_PUBLIC_LOCAL:
4007                         add_trace("cause", "location", "2-Local-Exchange");
4008                         break;
4009                         case LOCATION_TRANSIT:
4010                         add_trace("cause", "location", "3-Transit");
4011                         break;
4012                         case LOCATION_PUBLIC_REMOTE:
4013                         add_trace("cause", "location", "4-Remote-Exchange");
4014                         break;
4015                         case LOCATION_PRIVATE_REMOTE:
4016                         add_trace("cause", "location", "5-Remote-PBX");
4017                         break;
4018                         case LOCATION_INTERNATIONAL:
4019                         add_trace("cause", "location", "7-International-Exchange");
4020                         break;
4021                         case LOCATION_BEYOND:
4022                         add_trace("cause", "location", "10-Beyond-Interworking");
4023                         break;
4024                         default:
4025                         add_trace("cause", "location", "%d", param->disconnectinfo.location);
4026                 }
4027                 if (param->disconnectinfo.display[0])
4028                         add_trace("display", NULL, "%s", param->disconnectinfo.display);
4029                 end_trace();
4030                 break;
4031
4032                 case MESSAGE_NOTIFY:
4033                 switch(param->notifyinfo.notify) {
4034                         case 0x00:
4035                         logtext = "NULL";
4036                         break;
4037                         case 0x80:
4038                         logtext = "USER_SUSPENDED";
4039                         break;
4040                         case 0x82:
4041                         logtext = "BEARER_SERVICE_CHANGED";
4042                         break;
4043                         case 0x81:
4044                         logtext = "USER_RESUMED";
4045                         break;
4046                         case 0xc2:
4047                         logtext = "CONFERENCE_ESTABLISHED";
4048                         break;
4049                         case 0xc3:
4050                         logtext = "CONFERENCE_DISCONNECTED";
4051                         break;
4052                         case 0xc4:
4053                         logtext = "OTHER_PARTY_ADDED";
4054                         break;
4055                         case 0xc5:
4056                         logtext = "ISOLATED";
4057                         break;
4058                         case 0xc6:
4059                         logtext = "REATTACHED";
4060                         break;
4061                         case 0xc7:
4062                         logtext = "OTHER_PARTY_ISOLATED";
4063                         break;
4064                         case 0xc8:
4065                         logtext = "OTHER_PARTY_REATTACHED";
4066                         break;
4067                         case 0xc9:
4068                         logtext = "OTHER_PARTY_SPLIT";
4069                         break;
4070                         case 0xca:
4071                         logtext = "OTHER_PARTY_DISCONNECTED";
4072                         break;
4073                         case 0xcb:
4074                         logtext = "CONFERENCE_FLOATING";
4075                         break;
4076                         case 0xcc:
4077                         logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4078                         break;
4079                         case 0xcf:
4080                         logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4081                         break;
4082                         case 0xe0:
4083                         logtext = "CALL_IS_A_WAITING_CALL";
4084                         break;
4085                         case 0xe8:
4086                         logtext = "DIVERSION_ACTIVATED";
4087                         break;
4088                         case 0xe9:
4089                         logtext = "RESERVED_CT_1";
4090                         break;
4091                         case 0xea:
4092                         logtext = "RESERVED_CT_2";
4093                         break;
4094                         case 0xee:
4095                         logtext = "REVERSE_CHARGING";
4096                         break;
4097                         case 0xf9:
4098                         logtext = "REMOTE_HOLD";
4099                         break;
4100                         case 0xfa:
4101                         logtext = "REMOTE_RETRIEVAL";
4102                         break;
4103                         case 0xfb:
4104                         logtext = "CALL_IS_DIVERTING";
4105                         break;
4106                         default:
4107                         SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4108                         logtext = buffer;
4109
4110                 }
4111                 trace_header("NOTIFY", dir);
4112                 if (dir == DIRECTION_OUT)
4113                         add_trace("to", NULL, "CH(%lu)", port_id);
4114                 if (dir == DIRECTION_IN)
4115                         add_trace("from", NULL, "CH(%lu)", port_id);
4116                 if (param->notifyinfo.notify)
4117                         add_trace("indicator", NULL, "%s", logtext);
4118                 if (param->notifyinfo.id[0]) {
4119                         add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4120                         switch(param->notifyinfo.present) {
4121                                 case INFO_PRESENT_RESTRICTED:
4122                                 add_trace("redir'on", "present", "restricted");
4123                                 break;
4124                                 case INFO_PRESENT_ALLOWED:
4125                                 add_trace("redir'on", "present", "allowed");
4126                                 break;
4127                                 default:
4128                                 add_trace("redir'on", "present", "not available");
4129                         }
4130                 }
4131                 if (param->notifyinfo.display[0])
4132                         add_trace("display", NULL, "%s", param->notifyinfo.display);
4133                 end_trace();
4134                 break;
4135
4136                 case MESSAGE_PROGRESS:
4137                 switch(param->progressinfo.progress) {
4138                         case 0x01:
4139                         logtext = "Call is not end to end ISDN";
4140                         break;
4141                         case 0x02:
4142                         logtext = "Destination address is non-ISDN";
4143                         break;
4144                         case 0x03:
4145                         logtext = "Origination address is non-ISDN";
4146                         break;
4147                         case 0x04:
4148                         logtext = "Call has returned to the ISDN";
4149                         break;
4150                         case 0x08:
4151                         logtext = "In-band info or pattern available";
4152                         break;
4153                         default:
4154                         SPRINT(buffer, "%d", param->progressinfo.progress);
4155                         logtext = buffer;
4156
4157                 }
4158                 trace_header("PROGRESS", dir);
4159                 if (dir == DIRECTION_OUT)
4160                         add_trace("to", NULL, "CH(%lu)", port_id);
4161                 if (dir == DIRECTION_IN)
4162                         add_trace("from", NULL, "CH(%lu)", port_id);
4163                 add_trace("indicator", NULL, "%s", logtext);
4164                 switch(param->progressinfo.location) {
4165                         case LOCATION_USER:
4166                         add_trace("cause", "location", "0-User");
4167                         break;
4168                         case LOCATION_PRIVATE_LOCAL:
4169                         add_trace("cause", "location", "1-Local-PBX");
4170                         break;
4171                         case LOCATION_PUBLIC_LOCAL:
4172                         add_trace("cause", "location", "2-Local-Exchange");
4173                         break;
4174                         case LOCATION_TRANSIT:
4175                         add_trace("cause", "location", "3-Transit");
4176                         break;
4177                         case LOCATION_PUBLIC_REMOTE:
4178                         add_trace("cause", "location", "4-Remote-Exchange");
4179                         break;
4180                         case LOCATION_PRIVATE_REMOTE:
4181                         add_trace("cause", "location", "5-Remote-PBX");
4182                         break;
4183                         case LOCATION_INTERNATIONAL:
4184                         add_trace("cause", "location", "7-International-Exchange");
4185                         break;
4186                         case LOCATION_BEYOND:
4187                         add_trace("cause", "location", "10-Beyond-Interworking");
4188                         break;
4189                         default:
4190                         add_trace("cause", "location", "%d", param->progressinfo.location);
4191                 }
4192                 end_trace();
4193                 break;
4194
4195                 case MESSAGE_INFORMATION:
4196                 trace_header("INFORMATION", dir);
4197                 if (dir == DIRECTION_OUT)
4198                         add_trace("to", NULL, "CH(%lu)", port_id);
4199                 if (dir == DIRECTION_IN)
4200                         add_trace("from", NULL, "CH(%lu)", port_id);
4201                 if (param->information.id[0])
4202                         add_trace("dialing", NULL, "%s", param->information.id);
4203                 if (param->information.display[0])
4204                         add_trace("display", NULL, "%s", param->information.display);
4205                 if (param->information.sending_complete)
4206                         add_trace("complete", NULL, "true", param->information.sending_complete);
4207                 end_trace();
4208                 break;
4209
4210                 case MESSAGE_FACILITY:
4211                 trace_header("FACILITY", dir);
4212                 if (dir == DIRECTION_OUT)
4213                         add_trace("to", NULL, "CH(%lu)", port_id);
4214                 if (dir == DIRECTION_IN)
4215                         add_trace("from", NULL, "CH(%lu)", port_id);
4216                 end_trace();
4217                 break;
4218
4219                 case MESSAGE_TONE:
4220                 trace_header("TONE", dir);
4221                 if (dir == DIRECTION_OUT)
4222                         add_trace("to", NULL, "CH(%lu)", port_id);
4223                 if (dir == DIRECTION_IN)
4224                         add_trace("from", NULL, "CH(%lu)", port_id);
4225                 if (param->tone.name[0]) {
4226                         add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4227                         add_trace("name", NULL, "%s", param->tone.name);
4228                 } else
4229                         add_trace("off", NULL, NULL);
4230                 end_trace();
4231                 break;
4232
4233                 case MESSAGE_SUSPEND:
4234                 case MESSAGE_RESUME:
4235                 if (message_type == MESSAGE_SUSPEND)
4236                         trace_header("SUSPEND", dir);
4237                 else
4238                         trace_header("RESUME", dir);
4239                 if (dir == DIRECTION_OUT)
4240                         add_trace("to", NULL, "CH(%lu)", port_id);
4241                 if (dir == DIRECTION_IN)
4242                         add_trace("from", NULL, "CH(%lu)", port_id);
4243                 if (param->parkinfo.len)
4244                         add_trace("length", NULL, "%d", param->parkinfo.len);
4245                 end_trace();
4246                 break;
4247
4248 #if 0
4249                 case MESSAGE_BCHANNEL:
4250                 trace_header("BCHANNEL", dir);
4251                 switch(param->bchannel.type) {
4252                         case BCHANNEL_REQUEST:
4253                         add_trace("type", NULL, "request");
4254                         break;
4255                         case BCHANNEL_ASSIGN:
4256                         add_trace("type", NULL, "assign");
4257                         break;
4258                         case BCHANNEL_ASSIGN_ACK:
4259                         add_trace("type", NULL, "assign_ack");
4260                         break;
4261                         case BCHANNEL_REMOVE:
4262                         add_trace("type", NULL, "remove");
4263                         break;
4264                         case BCHANNEL_REMOVE_ACK:
4265                         add_trace("type", NULL, "remove_ack");
4266                         break;
4267                 }
4268                 if (param->bchannel.addr)
4269                         add_trace("address", NULL, "%x", param->bchannel.addr);
4270                 end_trace();
4271                 break;
4272 #endif
4273
4274                 default:
4275                 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4276         }
4277 }
4278
4279 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4280 {
4281         struct lcr_msg *message;
4282
4283         if (!portlist)
4284                 return;
4285         if (!portlist->port_id)
4286                 return;
4287
4288         if (!e_connectedmode) {
4289                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4290                 message->param.disconnectinfo.cause = cause;
4291                 message->param.disconnectinfo.location = location;
4292                 if (display[0])
4293                         SCPY(message->param.disconnectinfo.display, display);
4294                 else
4295                         SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4296         } else {
4297                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4298                 if (display[0])
4299                         SCPY(message->param.notifyinfo.display, display);
4300                 else
4301                         SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4302         }
4303         message_put(message);
4304         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
4305 }
4306