Fixed forwarding of sending-complete information.
[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_FACILITY */
2473 void EndpointAppPBX::port_facility(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         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2480         memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2481         message_put(message);
2482 }
2483
2484 /* port MESSAGE_SUSPEND */
2485 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2486 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2487 {
2488         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2489
2490         /* epoint is now parked */
2491         ea_endpoint->ep_park = 1;
2492         memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2493         ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2494
2495         /* remove port relation */
2496         ea_endpoint->free_portlist(portlist);
2497 }
2498
2499 /* port MESSAGE_RESUME */
2500 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2501 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2502 {
2503         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2504
2505         /* epoint is now resumed */
2506         ea_endpoint->ep_park = 0;
2507
2508 }
2509
2510
2511 /* port sends message to the endpoint
2512  */
2513 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2514 {
2515         struct port_list *portlist;
2516
2517         portlist = ea_endpoint->ep_portlist;
2518         while(portlist) {
2519                 if (port_id == portlist->port_id)
2520                         break;
2521                 portlist = portlist->next;
2522         }
2523         if (!portlist) {
2524                 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);
2525                 return;
2526         }
2527
2528 //      PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2529         switch(message_type) {
2530                 case MESSAGE_DATA: /* data from port */
2531                 /* check if there is a call */
2532                 if (!ea_endpoint->ep_join_id)
2533                         break;
2534                 /* continue if only one portlist */
2535                 if (ea_endpoint->ep_portlist->next != NULL)
2536                         break;
2537                 /* forward message */
2538                 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);  
2539                 break;
2540
2541                 case MESSAGE_TONE_EOF: /* tone is end of file */
2542                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2543                 if (e_action) {
2544                         if (e_action->index == ACTION_VBOX_PLAY) {
2545                                 vbox_message_eof();
2546                         }
2547                         if (e_action->index == ACTION_EFI) {
2548                                 efi_message_eof();
2549                         }
2550                 }
2551                 break;
2552
2553                 case MESSAGE_TONE_COUNTER: /* counter info received */
2554                 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);
2555                 if (e_action)
2556                 if (e_action->index == ACTION_VBOX_PLAY) {
2557                         e_vbox_counter = param->counter.current;
2558                         if (param->counter.max >= 0)
2559                                 e_vbox_counter_max = param->counter.max;
2560                 }
2561                 break;
2562
2563                 /* PORT sends SETUP message */
2564                 case MESSAGE_SETUP:
2565                 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);
2566                 if (e_state!=EPOINT_STATE_IDLE) {
2567                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2568                         break;
2569                 }
2570                 port_setup(portlist, message_type, param);
2571                 break;
2572
2573                 /* PORT sends INFORMATION message */
2574                 case MESSAGE_INFORMATION: /* additional digits received */
2575                 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);
2576                 port_information(portlist, message_type, param);
2577                 break;
2578
2579                 /* PORT sends FACILITY message */
2580                 case MESSAGE_FACILITY:
2581                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2582                 port_facility(portlist, message_type, param);
2583                 break;
2584
2585                 /* PORT sends DTMF message */
2586                 case MESSAGE_DTMF: /* dtmf digits received */
2587                 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);
2588                 port_dtmf(portlist, message_type, param);
2589                 break;
2590
2591                 /* PORT sends CRYPT message */
2592                 case MESSAGE_CRYPT: /* crypt response received */
2593                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2594                 port_crypt(portlist, message_type, param);
2595                 break;
2596
2597                 /* PORT sends MORE message */
2598                 case MESSAGE_OVERLAP:
2599                 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);
2600                 if (e_state != EPOINT_STATE_OUT_SETUP) {
2601                         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);
2602                         break;
2603                 }
2604                 port_overlap(portlist, message_type, param);
2605                 break;
2606
2607                 /* PORT sends PROCEEDING message */
2608                 case MESSAGE_PROCEEDING: /* port is proceeding */
2609                 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);
2610                 if (e_state!=EPOINT_STATE_OUT_SETUP
2611                  && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2612                         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);
2613                         break;
2614                 }
2615                 port_proceeding(portlist, message_type, param);
2616                 break;
2617
2618                 /* PORT sends ALERTING message */
2619                 case MESSAGE_ALERTING:
2620                 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);
2621                 if (e_state!=EPOINT_STATE_OUT_SETUP
2622                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2623                  && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2624                         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);
2625                         break;
2626                 }
2627                 port_alerting(portlist, message_type, param);
2628                 break;
2629
2630                 /* PORT sends CONNECT message */
2631                 case MESSAGE_CONNECT:
2632                 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);
2633                 if (e_state!=EPOINT_STATE_OUT_SETUP
2634                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2635                  && e_state!=EPOINT_STATE_OUT_PROCEEDING
2636                  && e_state!=EPOINT_STATE_OUT_ALERTING) {
2637                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2638                         break;
2639                 }
2640                 port_connect(portlist, message_type, param);
2641                 break;
2642
2643                 /* PORT sends DISCONNECT message */
2644                 case MESSAGE_DISCONNECT: /* port is disconnected */
2645                 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);
2646                 port_disconnect_release(portlist, message_type, param);
2647                 break;
2648
2649                 /* PORT sends a RELEASE message */
2650                 case MESSAGE_RELEASE: /* port releases */
2651                 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);
2652                 /* portlist is release at port_disconnect_release, thanx Paul */
2653                 port_disconnect_release(portlist, message_type, param);
2654                 break;
2655
2656                 /* PORT sends a TIMEOUT message */
2657                 case MESSAGE_TIMEOUT:
2658                 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);
2659                 port_timeout(portlist, message_type, param);
2660                 break; /* release */
2661
2662                 /* PORT sends a NOTIFY message */
2663                 case MESSAGE_NOTIFY:
2664                 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);
2665                 port_notify(portlist, message_type, param);
2666                 break;
2667
2668                 /* PORT sends a SUSPEND message */
2669                 case MESSAGE_SUSPEND:
2670                 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);
2671                 port_suspend(portlist, message_type, param);
2672                 break; /* suspend */
2673
2674                 /* PORT sends a RESUME message */
2675                 case MESSAGE_RESUME:
2676                 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);
2677                 port_resume(portlist, message_type, param);
2678                 break;
2679
2680 #if 0
2681                 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2682                 /* port assigns bchannel */
2683                 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2684                 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);
2685                 /* only one port is expected to be connected to bchannel */
2686                 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2687                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2688                 break;
2689 #endif
2690
2691
2692                 default:
2693                 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);
2694         }
2695
2696         /* Note: this endpoint may be destroyed, so we MUST return */
2697 }
2698
2699
2700 /* messages from join
2701  */
2702 /* join MESSAGE_CRYPT */
2703 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2704 {
2705         switch(param->crypt.type) {
2706                 /* message from remote port to "crypt manager" */
2707                 case CU_ACTK_REQ:           /* activate key-exchange */
2708                 case CU_ACTS_REQ:            /* activate shared key */
2709                 case CU_DACT_REQ:          /* deactivate */
2710                 case CU_INFO_REQ:         /* request last info message */
2711                 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2712                 break;
2713
2714                 /* message from "crypt manager" to user */
2715                 case CU_ACTK_CONF:          /* key-echange done */
2716                 case CU_ACTS_CONF:          /* shared key done */
2717                 case CU_DACT_CONF:           /* deactivated */
2718                 case CU_DACT_IND:           /* deactivated */
2719                 case CU_ERROR_IND:         /* receive error message */
2720                 case CU_INFO_IND:         /* receive info message */
2721                 case CU_INFO_CONF:         /* receive info message */
2722                 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2723                 break;
2724
2725                 default:
2726                 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);
2727         }
2728 }
2729
2730 /* join MESSAGE_INFORMATION */
2731 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2732 {
2733         struct lcr_msg *message;
2734
2735         e_overlap = 1;
2736
2737         while(portlist) {
2738                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2739                 memcpy(&message->param.information, &param->information, sizeof(struct dialing_info));
2740                 message_put(message);
2741                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2742                 portlist = portlist->next;
2743         }
2744 }
2745
2746 /* join MESSAGE_FACILITY */
2747 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2748 {
2749         struct lcr_msg *message;
2750
2751         if (!e_ext.facility && e_ext.number[0]) {
2752                 return;
2753         }
2754
2755         while(portlist) {
2756                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2757                 memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2758                 message_put(message);
2759                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2760                 portlist = portlist->next;
2761         }
2762 }
2763
2764 /* join MESSAGE_MORE */
2765 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2766 {
2767         struct lcr_msg *message;
2768
2769         new_state(EPOINT_STATE_IN_OVERLAP);
2770         
2771         /* own dialtone */
2772         if (e_join_pattern && e_ext.own_setup) {
2773                 /* disconnect audio */
2774                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2775                 message->param.audiopath = 0;
2776                 message_put(message);
2777         }
2778         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2779                         if (e_dialinginfo.id[0])
2780                                 set_tone(portlist, "dialing");
2781                         else
2782                                 set_tone(portlist, "dialtone");
2783                         return;
2784         }
2785         if (e_dialinginfo.id[0]) {
2786                 set_tone(portlist, "dialing");
2787         } else {
2788                 if (e_ext.number[0])
2789                         set_tone(portlist, "dialpbx");
2790                 else
2791                         set_tone(portlist, "dialtone");
2792         }
2793 }
2794
2795 /* join MESSAGE_PROCEEDING */
2796 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2797 {
2798         struct lcr_msg *message;
2799
2800         new_state(EPOINT_STATE_IN_PROCEEDING);
2801
2802         /* own proceeding tone */
2803         if (e_join_pattern) {
2804                 /* connect / disconnect audio */
2805                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2806                 if (e_ext.own_proceeding)
2807                         message->param.audiopath = 0;
2808                 else
2809                         message->param.audiopath = 1;
2810                 message_put(message);
2811         }
2812 //                      UCPY(e_join_tone, "proceeding");
2813         if (portlist) {
2814                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2815                 message_put(message);
2816                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2817         }
2818         set_tone(portlist, "proceeding");
2819 }
2820
2821 /* join MESSAGE_ALERTING */
2822 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2823 {
2824         struct lcr_msg *message;
2825
2826         new_state(EPOINT_STATE_IN_ALERTING);
2827
2828         /* own alerting tone */
2829         if (e_join_pattern) {
2830                 /* connect / disconnect audio */
2831                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2832                 if (e_ext.own_alerting)
2833                         message->param.audiopath = 0;
2834                 else
2835                         message->param.audiopath = 1;
2836                 message_put(message);
2837         }
2838         if (portlist) {
2839                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2840                 message_put(message);
2841                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2842         }
2843         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2844                 set_tone(portlist, "ringing");
2845                 return;
2846         }
2847         if (e_ext.number[0])
2848                 set_tone(portlist, "ringpbx");
2849         else
2850                 set_tone(portlist, "ringing");
2851
2852         if (e_ext.number[0])
2853                 e_dtmf = 1; /* allow dtmf */
2854 }
2855
2856 /* join MESSAGE_CONNECT */
2857 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2858 {
2859         struct lcr_msg *message;
2860         time_t now;
2861
2862         new_state(EPOINT_STATE_CONNECT);
2863 //                      UCPY(e_join_tone, "");
2864 //                      
2865         if (e_ext.number[0])
2866                 e_dtmf = 1; /* allow dtmf */
2867
2868         e_powerdial_on = 0;
2869         unsched_timer(&e_powerdial_timeout);
2870         memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_callerinfo));
2871         if(portlist) {
2872                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2873                 memcpy(&message->param, param, sizeof(union parameter));
2874
2875                 /* screen clip if prefix is required */
2876                 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2877                         SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2878                         SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2879                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2880                 }
2881
2882                 /* use internal caller id */
2883                 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2884                         SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2885                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2886                 }
2887
2888                 /* handle restricted caller ids */
2889                 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);
2890                 /* display callerid if desired for extension */
2891                 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));
2892
2893                 /* use conp, if enabld */
2894 //              if (!e_ext.centrex)
2895 //                      message->param.connectinfo.name[0] = '\0';
2896
2897                 /* send connect */
2898                 message_put(message);
2899                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2900         }
2901         set_tone(portlist, NULL);
2902         e_join_pattern = 0;
2903         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2904         message->param.audiopath = 1;
2905         message_put(message);
2906         time(&now);
2907         e_start = now;
2908 }
2909
2910 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2911 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2912 {
2913         char cause[16];
2914         struct lcr_msg *message;
2915         struct port_list *portlist = NULL;
2916         time_t now;
2917
2918
2919         /* be sure that we are active */
2920         notify_active();
2921         e_tx_state = NOTIFY_STATE_ACTIVE;
2922
2923         /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2924         if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2925                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2926
2927                 /* set time for power dialing */
2928                 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2929                 e_powercount++;
2930
2931                 /* set redial tone */
2932                 if (ea_endpoint->ep_portlist) {
2933                         e_join_pattern = 0;
2934                 }
2935                 set_tone(ea_endpoint->ep_portlist, "redial");
2936                 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);
2937                 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2938                 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2939                         new_state(EPOINT_STATE_IN_PROCEEDING);
2940                         if (ea_endpoint->ep_portlist) {
2941                                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2942                                 message_put(message);
2943                                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2944                         }
2945 /* caused the error, that the first knock sound was not there */
2946 /*                                      set_tone(portlist, "proceeding"); */
2947                 }
2948                 /* send display of powerdialing */
2949                 if (e_ext.display_dialing) {
2950                         portlist = ea_endpoint->ep_portlist;
2951                         while (portlist) {
2952                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2953                                 if (e_powerlimit)
2954                                         SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2955                                 else
2956                                         SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2957                                 message_put(message);
2958                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2959                                 portlist = portlist->next;
2960                         }
2961                 }
2962                 return;
2963         }
2964
2965         /* set stop time */
2966         time(&now);
2967         e_stop = now;
2968
2969         if ((e_state!=EPOINT_STATE_CONNECT
2970           && e_state!=EPOINT_STATE_OUT_DISCONNECT
2971           && e_state!=EPOINT_STATE_IN_OVERLAP
2972           && e_state!=EPOINT_STATE_IN_PROCEEDING
2973           && e_state!=EPOINT_STATE_IN_ALERTING)
2974          || !ea_endpoint->ep_portlist) { /* or no port */
2975                 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2976                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2977                 return; /* must exit here */
2978         }
2979         /* save cause */
2980         if (!e_join_cause) {
2981                 e_join_cause = param->disconnectinfo.cause;
2982                 e_join_location = param->disconnectinfo.location;
2983         }
2984
2985         /* on release we need the audio again! */
2986         if (message_type == MESSAGE_RELEASE) {
2987                 e_join_pattern = 0;
2988                 ea_endpoint->ep_join_id = 0;
2989         }
2990         /* disconnect and select tone */
2991         new_state(EPOINT_STATE_OUT_DISCONNECT);
2992         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2993         /* if own_cause, we must release the join */
2994         if (e_ext.own_cause /* own cause */
2995          || !e_join_pattern) { /* no patterns */
2996                 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);
2997                 if (message_type != MESSAGE_RELEASE)
2998                         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2999                 e_join_pattern = 0;
3000         } else { /* else we enable audio */
3001                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3002                 message->param.audiopath = 1;
3003                 message_put(message);
3004         }
3005         /* send disconnect message */
3006         SCPY(e_tone, cause);
3007         portlist = ea_endpoint->ep_portlist;
3008         while(portlist) {
3009                 set_tone(portlist, cause);
3010                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3011                 portlist = portlist->next;
3012         }
3013 }
3014
3015 /* join MESSAGE_SETUP */
3016 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3017 {
3018         struct lcr_msg *message;
3019 //      struct interface        *interface;
3020
3021         /* if we already in setup state, we just update the dialing with new digits */
3022         if (e_state == EPOINT_STATE_OUT_SETUP
3023          || e_state == EPOINT_STATE_OUT_OVERLAP) {
3024                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3025                 /* if digits changed, what we have already dialed */
3026                 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3027                         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);
3028                         /* release all ports */
3029                         while((portlist = ea_endpoint->ep_portlist)) {
3030                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3031                                 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3032                                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3033                                 message_put(message);
3034                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3035                                 ea_endpoint->free_portlist(portlist);
3036                         }
3037
3038                         /* disconnect audio */
3039                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3040                         message->param.audiopath = 0;
3041                         message_put(message);
3042
3043                         /* get dialing info */
3044                         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3045                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3046                         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3047                         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3048                         new_state(EPOINT_STATE_OUT_OVERLAP);
3049
3050                         /* get time */
3051                         schedule_timer(&e_redial_timeout, 1, 0);
3052                         return;
3053                 }
3054                 /* if we have a pending redial, so we just adjust the dialing number */
3055                 if (e_redial_timeout.active) {
3056                         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);
3057                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3058                         return;
3059                 }
3060                 if (!ea_endpoint->ep_portlist) {
3061                         PERROR("ERROR: overlap dialing to a NULL port relation\n");
3062                 }
3063                 if (ea_endpoint->ep_portlist->next) {
3064                         PERROR("ERROR: overlap dialing to a port_list port relation\n");
3065                 }
3066                 if (e_state == EPOINT_STATE_OUT_SETUP) {
3067                         /* queue digits */
3068                         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);
3069                         SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3070                         
3071                 } else {
3072                         /* get what we have not dialed yet */
3073                         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));
3074                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3075                         SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3076                         message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3077                         message_put(message);
3078                         logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3079                 }
3080                 /* always store what we have dialed or queued */
3081                 memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3082                 
3083                 return;
3084         }
3085         if (e_state != EPOINT_STATE_IDLE) {
3086                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3087                 return;
3088         }
3089         /* if an internal extension is dialed, copy that number */
3090         if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3091                 SCPY(e_ext.number, param->setup.dialinginfo.id);
3092         /* if an internal extension is dialed, get extension's info about caller */
3093         if (e_ext.number[0]) {
3094                 if (!read_extension(&e_ext, e_ext.number)) {
3095                         e_ext.number[0] = '\0';
3096                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3097                 }
3098         }
3099
3100         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3101         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3102         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3103         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3104
3105         /* process (voice over) data calls */
3106         if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3107                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3108                 memset(&e_capainfo, 0, sizeof(e_capainfo));
3109                 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3110                 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3111                 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3112         }
3113
3114         new_state(EPOINT_STATE_OUT_SETUP);
3115         /* call special setup routine */
3116         out_setup();
3117 }
3118
3119 /* join MESSAGE_mISDNSIGNAL */
3120 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3121 {
3122         struct lcr_msg *message;
3123
3124         while(portlist) {
3125                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3126                 memcpy(&message->param, param, sizeof(union parameter));
3127                 message_put(message);
3128                 portlist = portlist->next;
3129         }
3130 }
3131
3132 /* join MESSAGE_NOTIFY */
3133 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3134 {
3135         struct lcr_msg *message;
3136         int new_state;
3137
3138         if (param->notifyinfo.notify) {
3139                 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3140 //              /* if notification was generated locally, we turn hold music on/off */ 
3141 //              if (param->notifyinfo.local)
3142 // 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)
3143                 {
3144                         if (e_hold) {
3145                                 /* unhold if */
3146                                 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3147                                         if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3148                                                 while(portlist) {
3149                                                         set_tone(portlist, "");
3150                                                         portlist = portlist->next;
3151                                                 }
3152                                         }
3153                                         portlist = ea_endpoint->ep_portlist;
3154                                         e_hold = 0;
3155                                 }
3156                         } else {
3157                                 /* hold if */
3158                                 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3159                                         while(portlist) {
3160                                                 set_tone(portlist, "hold");
3161                                                 portlist = portlist->next;
3162                                         }
3163                                         portlist = ea_endpoint->ep_portlist;
3164                                         e_hold = 1;
3165                                 }
3166                         }
3167                 }
3168                 /* save new state */
3169                 e_tx_state = new_state;
3170         }
3171
3172         /* notify port(s) about it */
3173         while(portlist) {
3174                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3175                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
3176                 /* handle restricted caller ids */
3177                 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3178                 /* display callerid if desired for extension */
3179                 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));
3180                 message_put(message);
3181                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3182                 portlist = portlist->next;
3183         }
3184 }
3185
3186 /* JOIN sends messages to the endpoint
3187  */
3188 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3189 {
3190         struct port_list *portlist;
3191         struct lcr_msg *message;
3192
3193         if (!join_id) {
3194                 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3195                 return;
3196         }
3197
3198         portlist = ea_endpoint->ep_portlist;
3199
3200         /* send MESSAGE_DATA to port */
3201         if (message_type == MESSAGE_DATA) {
3202                 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3203                         /* skip if no port relation */
3204                         if (!portlist)
3205                                 return;
3206                         /* skip if more than one port relation */
3207                         if (portlist->next)
3208                                 return;
3209                         /* forward audio data to port */
3210                         message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3211                         return;
3212                 }
3213         }
3214
3215 //      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);
3216         switch(message_type) {
3217                 /* JOIN SENDS TONE message */
3218                 case MESSAGE_TONE:
3219                 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);
3220                 set_tone(portlist, param->tone.name);
3221                 break;
3222
3223                 /* JOIN SENDS CRYPT message */
3224                 case MESSAGE_CRYPT:
3225                 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);
3226                 join_crypt(portlist, message_type, param);
3227                 break;
3228
3229                 /* JOIN sends INFORMATION message */
3230                 case MESSAGE_INFORMATION:
3231                 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);
3232                 join_information(portlist, message_type, param);
3233                 break;
3234
3235                 /* JOIN sends FACILITY message */
3236                 case MESSAGE_FACILITY:
3237                 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);
3238                 join_facility(portlist, message_type, param);
3239                 break;
3240
3241                 /* JOIN sends OVERLAP message */
3242                 case MESSAGE_OVERLAP:
3243                 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);
3244                 if (e_state!=EPOINT_STATE_IN_SETUP
3245                  && e_state!=EPOINT_STATE_IN_OVERLAP) {
3246                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3247                         break;
3248                 }
3249                 join_overlap(portlist, message_type, param);
3250                 break;
3251
3252                 /* JOIN sends PROCEEDING message */
3253                 case MESSAGE_PROCEEDING:
3254                 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);
3255                 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3256                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3257                         break;
3258                 }
3259                 join_proceeding(portlist, message_type, param);
3260                 break;
3261
3262                 /* JOIN sends ALERTING message */
3263                 case MESSAGE_ALERTING:
3264                 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);
3265                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3266                  && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3267                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3268                         break;
3269                 }
3270                 join_alerting(portlist, message_type, param);
3271                 break;
3272
3273                 /* JOIN sends CONNECT message */
3274                 case MESSAGE_CONNECT:
3275                 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);
3276                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3277                  && e_state!=EPOINT_STATE_IN_PROCEEDING
3278                  && e_state!=EPOINT_STATE_IN_ALERTING) {
3279                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3280                         break;
3281                 }
3282                 join_connect(portlist, message_type, param);
3283                 break;
3284
3285                 /* JOIN sends DISCONNECT/RELEASE message */
3286                 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3287                 case MESSAGE_RELEASE: /* JOIN releases */
3288                 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);
3289                 join_disconnect_release(message_type, param);
3290                 break;
3291
3292                 /* JOIN sends SETUP message */
3293                 case MESSAGE_SETUP:
3294                 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);
3295                 join_setup(portlist, message_type, param);
3296                 break;
3297
3298                 /* JOIN sends special mISDNSIGNAL message */
3299                 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3300                 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);
3301                 join_mISDNsignal(portlist, message_type, param);
3302                 break;
3303
3304 #if 0
3305                 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3306                 /* JOIN requests bchannel */
3307                 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3308                 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);
3309                 /* only one port is expected to be connected to bchannel */
3310                 if (!portlist)
3311                         break;
3312                 if (portlist->next)
3313                         break;
3314                 e_join_pattern = 1;
3315                 SCPY(e_tone, "");
3316                 set_tone(portlist, NULL);
3317                 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3318                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3319                 break;
3320 #endif
3321
3322                 /* JOIN has pattern available */
3323                 case MESSAGE_PATTERN: /* indicating pattern available */
3324                 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);
3325                 if (!e_join_pattern) {
3326                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3327                         e_join_pattern = 1;
3328                         SCPY(e_tone, "");
3329                         while(portlist) {
3330                                 set_tone(portlist, NULL);
3331                                 portlist = portlist->next;
3332                         }
3333                         /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3334                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3335                         message->param.audiopath = 1;
3336                         message_put(message);
3337                 }
3338                 break;
3339
3340                 /* JOIN has no pattern available */
3341                 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3342                 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);
3343                 if (e_join_pattern) {
3344                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3345                         e_join_pattern = 0;
3346                         /* disconnect our audio tx and rx */
3347                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3348                         message->param.audiopath = 0;
3349                         message_put(message);
3350                 }
3351                 break;
3352
3353 #if 0
3354                 /* JOIN (dunno at the moment) */
3355                 case MESSAGE_REMOTE_AUDIO:
3356                 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);
3357                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3358                 message->param.audiopath = param->channel;
3359                 message_put(message);
3360                 break;
3361 #endif
3362
3363                 /* JOIN sends a notify message */
3364                 case MESSAGE_NOTIFY:
3365                 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);
3366                 join_notify(portlist, message_type, param);
3367                 break;
3368
3369                 /* JOIN wants keypad / dtmf */
3370                 case MESSAGE_ENABLEKEYPAD:
3371                 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);
3372                 e_enablekeypad = 1;
3373                 e_dtmf = 1;
3374                 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3375                 end_trace();
3376                 break;
3377
3378                 default:
3379                 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);
3380         }
3381 }
3382
3383
3384 /* pick_join will connect the first incoming call found. the endpoint
3385  * will receivce a MESSAGE_CONNECT.
3386  */
3387 int match_list(char *list, char *item)
3388 {
3389         char *end, *next = NULL;
3390
3391         /* no list make matching */
3392         if (!list)
3393                 return(1);
3394
3395         while(42) {
3396                 /* eliminate white spaces */
3397                 while (*list <= ' ')
3398                         list++;
3399                 if (*list == ',') {
3400                         list++;
3401                         continue;
3402                 }
3403                 /* if end of list is reached, we return */
3404                 if (list[0] == '\0')
3405                         return(0);
3406                 /* if we have more than one entry (left) */
3407                 if ((end = strchr(list, ',')))
3408                         next = end + 1;
3409                 else
3410                         next = end = strchr(list, '\0');
3411                 while (*(end-1) <= ' ')
3412                         end--;
3413                 /* if string part matches item */
3414                 if (!strncmp(list, item, end-list))
3415                         return(1);
3416                 list = next;
3417         }
3418 }
3419
3420 void EndpointAppPBX::pick_join(char *extensions)
3421 {
3422         struct lcr_msg *message;
3423         struct port_list *portlist;
3424         class Port *port;
3425         class EndpointAppPBX *eapp, *found;
3426         class Join *join;
3427         class JoinPBX *joinpbx;
3428         struct join_relation *relation;
3429         int vbox;
3430
3431         /* find an endpoint that is ringing internally or vbox with higher priority */
3432         vbox = 0;
3433         found = NULL;
3434         eapp = apppbx_first;
3435         while(eapp) {
3436                 if (eapp!=this && ea_endpoint->ep_portlist) {
3437                         portlist = eapp->ea_endpoint->ep_portlist;
3438                         while(portlist) {
3439                                 if ((port = find_port_id(portlist->port_id))) {
3440                                         if (port->p_type == PORT_TYPE_VBOX_OUT) {
3441                                                 if (match_list(extensions, eapp->e_ext.number)) {
3442                                                         found = eapp;
3443                                                         vbox = 1;
3444                                                         break;
3445                                                 }
3446                                         }
3447                                         if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3448                                          && port->p_state==PORT_STATE_OUT_ALERTING)
3449                                                 if (match_list(extensions, eapp->e_ext.number)) {
3450                                                         found = eapp;
3451                                                 }
3452                                 }
3453                                 portlist = portlist->next;
3454                         }
3455                         if (portlist)
3456                                 break;
3457                 }
3458                 eapp = eapp->next;
3459         }
3460
3461         /* if no endpoint found */
3462         if (!found) {
3463                 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);
3464 reject:
3465                 set_tone(ea_endpoint->ep_portlist, "cause_10");
3466                 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3467                 new_state(EPOINT_STATE_OUT_DISCONNECT);
3468                 return;
3469         }
3470         eapp = found;
3471
3472         if (ea_endpoint->ep_join_id) {
3473                 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3474                 goto reject;
3475         }
3476         if (!eapp->ea_endpoint->ep_join_id) {
3477                 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3478                 goto reject;
3479         }
3480         join = find_join_id(eapp->ea_endpoint->ep_join_id);
3481         if (!join) {
3482                 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3483                 goto reject;
3484         }
3485         if (join->j_type != JOIN_TYPE_PBX) {
3486                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3487                 goto reject;
3488         }
3489         joinpbx = (class JoinPBX *)join;
3490         relation = joinpbx->j_relation;
3491         if (!relation) {
3492                 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3493                 goto reject;
3494         }
3495         while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3496                 relation = relation->next;
3497                 if (!relation) {
3498                         PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3499                         goto reject;
3500                 }
3501         }
3502
3503         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3504
3505         if (options.deb & DEBUG_EPOINT) {
3506                 class Join *debug_c = join_first;
3507                 class Endpoint *debug_e = epoint_first;
3508                 class Port *debug_p = port_first;
3509
3510                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3511
3512                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3513                 while(debug_c) {
3514                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3515                         debug_c = debug_c->next;
3516                 }
3517                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3518                 while(debug_e) {
3519                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3520                         debug_e = debug_e->next;
3521                 }
3522                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3523                 while(debug_p) {
3524                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3525                         debug_p = debug_p->next;
3526                 }
3527         }
3528
3529         /* relink join */
3530         ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3531         relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3532         eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3533
3534         /* connnecting our endpoint */
3535         new_state(EPOINT_STATE_CONNECT);
3536         if (e_ext.number[0])
3537                 e_dtmf = 1;
3538         set_tone(ea_endpoint->ep_portlist, NULL);
3539
3540         /* now we send a release to the ringing endpoint */
3541         message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3542         message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3543         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3544         message_put(message);
3545
3546         /* we send a connect to the join with our caller id */
3547         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3548         SCPY(message->param.connectinfo.id, e_callerinfo.id);
3549         message->param.connectinfo.present = e_callerinfo.present;
3550         message->param.connectinfo.screen = e_callerinfo.screen;
3551         message->param.connectinfo.itype = e_callerinfo.itype;
3552         message->param.connectinfo.ntype = e_callerinfo.ntype;
3553         message_put(message);
3554
3555         /* we send a connect to our port with the remote callerid */
3556         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3557         SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3558         message->param.connectinfo.present = eapp->e_callerinfo.present;
3559         message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3560         message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3561         message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3562         /* handle restricted caller ids */
3563         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);
3564         /* display callerid if desired for extension */
3565         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));
3566         message_put(message);
3567
3568         /* we send a connect to the audio path (not for vbox) */
3569         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3570         message->param.audiopath = 1;
3571         message_put(message);
3572
3573         /* beeing paranoid, we make call update */
3574         trigger_work(&joinpbx->j_updatebridge);
3575
3576         if (options.deb & DEBUG_EPOINT) {
3577                 class Join *debug_c = join_first;
3578                 class Endpoint *debug_e = epoint_first;
3579                 class Port *debug_p = port_first;
3580
3581                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3582
3583                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3584                 while(debug_c) {
3585                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3586                         debug_c = debug_c->next;
3587                 }
3588                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3589                 while(debug_e) {
3590                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3591                         debug_e = debug_e->next;
3592                 }
3593                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3594                 while(debug_p) {
3595                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3596                         debug_p = debug_p->next;
3597                 }
3598         }
3599 }
3600
3601
3602 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3603  */
3604 void EndpointAppPBX::join_join(void)
3605 {
3606         struct lcr_msg *message;
3607         struct join_relation *our_relation, *other_relation;
3608         struct join_relation **our_relation_pointer, **other_relation_pointer;
3609         class Join *our_join, *other_join;
3610         class JoinPBX *our_joinpbx, *other_joinpbx;
3611         class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3612         class Port *our_port, *other_port;
3613         class Pdss1 *our_pdss1, *other_pdss1;
3614
3615         /* are we a candidate to join a join? */
3616         our_join = find_join_id(ea_endpoint->ep_join_id);
3617         if (!our_join) {
3618                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3619                 return;
3620         }
3621         if (our_join->j_type != JOIN_TYPE_PBX) {
3622                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3623                 return;
3624         }
3625         our_joinpbx = (class JoinPBX *)our_join;
3626         if (!ea_endpoint->ep_portlist) {
3627                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3628                 return;
3629         }
3630         if (!e_ext.number[0]) {
3631                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3632                 return;
3633         }
3634         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3635         if (!our_port) {
3636                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3637                 return;
3638         }
3639         if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3640                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3641                 return;
3642         }
3643         our_pdss1 = (class Pdss1 *)our_port;
3644
3645         /* find an endpoint that is on hold and has the same mISDNport that we are on */
3646         other_eapp = apppbx_first;
3647         while(other_eapp) {
3648                 if (other_eapp == this) {
3649                         other_eapp = other_eapp->next;
3650                         continue;
3651                 }
3652                 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);
3653                 if (other_eapp->e_ext.number[0] /* has terminal */
3654                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3655                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3656                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3657                         if (other_port) { /* port still exists */
3658                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3659                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3660                                         other_pdss1 = (class Pdss1 *)other_port;
3661                                         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);
3662                                         if (other_pdss1->p_m_hold /* port is on hold */
3663                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3664                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3665                                                 break;
3666                                 } else {
3667                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3668                                 }
3669                         } else {
3670                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3671                         }
3672                 }
3673                 other_eapp = other_eapp->next;
3674         }
3675         if (!other_eapp) {
3676                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3677                 return;
3678         }
3679         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3680
3681         /* if we have the same join */
3682         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3683                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3684                 return;
3685         }
3686         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3687         if (!other_join) {
3688                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3689                 return;
3690         }
3691         if (other_join->j_type != JOIN_TYPE_PBX) {
3692                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3693                 return;
3694         }
3695         other_joinpbx = (class JoinPBX *)other_join;
3696         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3697                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3698                 return;
3699         }
3700
3701         /* remove relation to endpoint for join on hold */
3702         other_relation = other_joinpbx->j_relation;
3703         other_relation_pointer = &other_joinpbx->j_relation;
3704         while(other_relation) {
3705                 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3706                         /* detach other endpoint on hold */
3707                         *other_relation_pointer = other_relation->next;
3708                         FREE(other_relation, sizeof(struct join_relation));
3709                         cmemuse--;
3710                         other_relation = *other_relation_pointer;
3711                         other_eapp->ea_endpoint->ep_join_id = 0;
3712                         continue;
3713                 }
3714
3715                 /* change join/hold pointer of endpoint to the new join */
3716                 temp_epoint = find_epoint_id(other_relation->epoint_id);
3717                 if (temp_epoint) {
3718                         if (temp_epoint->ep_join_id == other_join->j_serial)
3719                                 temp_epoint->ep_join_id = our_join->j_serial;
3720                 }
3721
3722                 other_relation_pointer = &other_relation->next;
3723                 other_relation = other_relation->next;
3724         }
3725         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3726
3727         /* join call relations */
3728         our_relation = our_joinpbx->j_relation;
3729         our_relation_pointer = &our_joinpbx->j_relation;
3730         while(our_relation) {
3731                 our_relation_pointer = &our_relation->next;
3732                 our_relation = our_relation->next;
3733         }
3734         *our_relation_pointer = other_joinpbx->j_relation;
3735         other_joinpbx->j_relation = NULL;
3736         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3737
3738         /* release endpoint on hold */
3739         message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3740         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3741         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3742         message_put(message);
3743         
3744         /* if we are not a partyline, we get partyline state from other join */
3745         our_joinpbx->j_partyline += other_joinpbx->j_partyline; 
3746
3747         /* remove empty join */
3748         delete other_join;
3749         PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3750
3751         /* mixer must update */
3752         trigger_work(&our_joinpbx->j_updatebridge);
3753
3754         /* we send a retrieve to that endpoint */
3755         // mixer will update the hold-state of the join and send it to the endpoints is changes
3756 }
3757
3758
3759 /* check if we have an external call
3760  * this is used to check for encryption ability
3761  */
3762 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3763 {
3764         struct join_relation *relation;
3765         class Join *join;
3766         class JoinPBX *joinpbx;
3767         class Endpoint *epoint;
3768
3769         /* some paranoia check */
3770         if (!ea_endpoint->ep_portlist) {
3771                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3772                 *errstr = "No Call";
3773                 return(1);
3774         }
3775         if (!e_ext.number[0]) {
3776                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3777                 *errstr = "No Call";
3778                 return(1);
3779         }
3780
3781         /* check if we have a join with 2 parties */
3782         join = find_join_id(ea_endpoint->ep_join_id);
3783         if (!join) {
3784                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3785                 *errstr = "No Call";
3786                 return(1);
3787         }
3788         if (join->j_type != JOIN_TYPE_PBX) {
3789                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3790                 *errstr = "No PBX Call";
3791                 return(1);
3792         }
3793         joinpbx = (class JoinPBX *)join;
3794         relation = joinpbx->j_relation;
3795         if (!relation) {
3796                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3797                 *errstr = "No Call";
3798                 return(1);
3799         }
3800         if (!relation->next) {
3801                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3802                 *errstr = "No Call";
3803                 return(1);
3804         }
3805         if (relation->next->next) {
3806                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3807                 *errstr = "Err: Conference";
3808                 return(1);
3809         }
3810         if (relation->epoint_id == ea_endpoint->ep_serial) {
3811                 relation = relation->next;
3812                 if (relation->epoint_id == ea_endpoint->ep_serial) {
3813                         PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3814                         *errstr = "Software Error";
3815                         return(1);
3816                 }
3817         }
3818
3819         /* check remote port for external call */
3820         epoint = find_epoint_id(relation->epoint_id);
3821         if (!epoint) {
3822                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3823                 *errstr = "No Call";
3824                 return(1);
3825         }
3826         if (!epoint->ep_portlist) {
3827                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3828                 *errstr = "No Call";
3829                 return(1);
3830         }
3831         *port = find_port_id(epoint->ep_portlist->port_id);
3832         if (!(*port)) {
3833                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3834                 *errstr = "No Call";
3835                 return(1);
3836         }
3837         if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3838                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3839                 *errstr = "No Ext Call";
3840                 return(1);
3841         }
3842         if ((*port)->p_state != PORT_STATE_CONNECT) {
3843                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3844                 *errstr = "No Ext Connect";
3845                 return(1);
3846         }
3847         return(0);
3848 }
3849
3850 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3851 {
3852         const char *logtext = "unknown";
3853         char buffer[64];
3854
3855         switch(message_type) {
3856                 case MESSAGE_SETUP:
3857                 trace_header("SETUP", dir);
3858                 if (dir == DIRECTION_OUT)
3859                         add_trace("to", NULL, "CH(%lu)", port_id);
3860                 if (dir == DIRECTION_IN)
3861                         add_trace("from", NULL, "CH(%lu)", port_id);
3862                 if (param->setup.callerinfo.extension[0])
3863                         add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3864                 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3865                 switch(param->setup.callerinfo.present) {
3866                         case INFO_PRESENT_RESTRICTED:
3867                         add_trace("caller id", "present", "restricted");
3868                         break;
3869                         case INFO_PRESENT_ALLOWED:
3870                         add_trace("caller id", "present", "allowed");
3871                         break;
3872                         default:
3873                         add_trace("caller id", "present", "not available");
3874                 }
3875                 if (param->setup.callerinfo.ntype2) {
3876                         add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3877                         switch(param->setup.callerinfo.present) {
3878                                 case INFO_PRESENT_RESTRICTED:
3879                                 add_trace("caller id2", "present", "restricted");
3880                                 break;
3881                                 case INFO_PRESENT_ALLOWED:
3882                                 add_trace("caller id2", "present", "allowed");
3883                                 break;
3884                                 default:
3885                                 add_trace("caller id2", "present", "not available");
3886                         }
3887                 }
3888                 if (param->setup.redirinfo.id[0]) {
3889                         add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3890                         switch(param->setup.redirinfo.present) {
3891                                 case INFO_PRESENT_RESTRICTED:
3892                                 add_trace("redir'ing", "present", "restricted");
3893                                 break;
3894                                 case INFO_PRESENT_ALLOWED:
3895                                 add_trace("redir'ing", "present", "allowed");
3896                                 break;
3897                                 default:
3898                                 add_trace("redir'ing", "present", "not available");
3899                         }
3900                 }
3901                 if (param->setup.dialinginfo.id[0])
3902                         add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3903                 if (param->setup.dialinginfo.keypad[0])
3904                         add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3905                 if (param->setup.dialinginfo.display[0])
3906                         add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3907                 if (param->setup.dialinginfo.sending_complete)
3908                         add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3909                 end_trace();
3910                 break;
3911
3912                 case MESSAGE_OVERLAP:
3913                 trace_header("SETUP ACKNOWLEDGE", dir);
3914                 if (dir == DIRECTION_OUT)
3915                         add_trace("to", NULL, "CH(%lu)", port_id);
3916                 if (dir == DIRECTION_IN)
3917                         add_trace("from", NULL, "CH(%lu)", port_id);
3918                 end_trace();
3919                 break;
3920
3921                 case MESSAGE_PROCEEDING:
3922                 trace_header("PROCEEDING", dir);
3923                 if (dir == DIRECTION_OUT)
3924                         add_trace("to", NULL, "CH(%lu)", port_id);
3925                 if (dir == DIRECTION_IN)
3926                         add_trace("from", NULL, "CH(%lu)", port_id);
3927                 end_trace();
3928                 break;
3929
3930                 case MESSAGE_ALERTING:
3931                 trace_header("ALERTING", dir);
3932                 if (dir == DIRECTION_OUT)
3933                         add_trace("to", NULL, "CH(%lu)", port_id);
3934                 if (dir == DIRECTION_IN)
3935                         add_trace("from", NULL, "CH(%lu)", port_id);
3936                 end_trace();
3937                 break;
3938
3939                 case MESSAGE_CONNECT:
3940                 trace_header("CONNECT", dir);
3941                 if (dir == DIRECTION_OUT)
3942                         add_trace("to", NULL, "CH(%lu)", port_id);
3943                 if (dir == DIRECTION_IN)
3944                         add_trace("from", NULL, "CH(%lu)", port_id);
3945                 if (param->connectinfo.extension[0])
3946                         add_trace("extension", NULL, "%s", param->connectinfo.extension);
3947                 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3948                 switch(param->connectinfo.present) {
3949                         case INFO_PRESENT_RESTRICTED:
3950                         add_trace("connect id", "present", "restricted");
3951                         break;
3952                         case INFO_PRESENT_ALLOWED:
3953                         add_trace("connect id", "present", "allowed");
3954                         break;
3955                         default:
3956                         add_trace("connect id", "present", "not available");
3957                 }
3958                 if (param->connectinfo.display[0])
3959                         add_trace("display", NULL, "%s", param->connectinfo.display);
3960                 end_trace();
3961                 break;
3962
3963                 case MESSAGE_DISCONNECT:
3964                 case MESSAGE_RELEASE:
3965                 if (message_type == MESSAGE_DISCONNECT)
3966                         trace_header("DISCONNECT", dir);
3967                 else
3968                         trace_header("RELEASE", dir);
3969                 if (dir == DIRECTION_OUT)
3970                         add_trace("to", NULL, "CH(%lu)", port_id);
3971                 if (dir == DIRECTION_IN)
3972                         add_trace("from", NULL, "CH(%lu)", port_id);
3973                 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3974                 switch(param->disconnectinfo.location) {
3975                         case LOCATION_USER:
3976                         add_trace("cause", "location", "0-User");
3977                         break;
3978                         case LOCATION_PRIVATE_LOCAL:
3979                         add_trace("cause", "location", "1-Local-PBX");
3980                         break;
3981                         case LOCATION_PUBLIC_LOCAL:
3982                         add_trace("cause", "location", "2-Local-Exchange");
3983                         break;
3984                         case LOCATION_TRANSIT:
3985                         add_trace("cause", "location", "3-Transit");
3986                         break;
3987                         case LOCATION_PUBLIC_REMOTE:
3988                         add_trace("cause", "location", "4-Remote-Exchange");
3989                         break;
3990                         case LOCATION_PRIVATE_REMOTE:
3991                         add_trace("cause", "location", "5-Remote-PBX");
3992                         break;
3993                         case LOCATION_INTERNATIONAL:
3994                         add_trace("cause", "location", "7-International-Exchange");
3995                         break;
3996                         case LOCATION_BEYOND:
3997                         add_trace("cause", "location", "10-Beyond-Interworking");
3998                         break;
3999                         default:
4000                         add_trace("cause", "location", "%d", param->disconnectinfo.location);
4001                 }
4002                 if (param->disconnectinfo.display[0])
4003                         add_trace("display", NULL, "%s", param->disconnectinfo.display);
4004                 end_trace();
4005                 break;
4006
4007                 case MESSAGE_NOTIFY:
4008                 switch(param->notifyinfo.notify) {
4009                         case 0x00:
4010                         logtext = "NULL";
4011                         break;
4012                         case 0x80:
4013                         logtext = "USER_SUSPENDED";
4014                         break;
4015                         case 0x82:
4016                         logtext = "BEARER_SERVICE_CHANGED";
4017                         break;
4018                         case 0x81:
4019                         logtext = "USER_RESUMED";
4020                         break;
4021                         case 0xc2:
4022                         logtext = "CONFERENCE_ESTABLISHED";
4023                         break;
4024                         case 0xc3:
4025                         logtext = "CONFERENCE_DISCONNECTED";
4026                         break;
4027                         case 0xc4:
4028                         logtext = "OTHER_PARTY_ADDED";
4029                         break;
4030                         case 0xc5:
4031                         logtext = "ISOLATED";
4032                         break;
4033                         case 0xc6:
4034                         logtext = "REATTACHED";
4035                         break;
4036                         case 0xc7:
4037                         logtext = "OTHER_PARTY_ISOLATED";
4038                         break;
4039                         case 0xc8:
4040                         logtext = "OTHER_PARTY_REATTACHED";
4041                         break;
4042                         case 0xc9:
4043                         logtext = "OTHER_PARTY_SPLIT";
4044                         break;
4045                         case 0xca:
4046                         logtext = "OTHER_PARTY_DISCONNECTED";
4047                         break;
4048                         case 0xcb:
4049                         logtext = "CONFERENCE_FLOATING";
4050                         break;
4051                         case 0xcc:
4052                         logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4053                         break;
4054                         case 0xcf:
4055                         logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4056                         break;
4057                         case 0xe0:
4058                         logtext = "CALL_IS_A_WAITING_CALL";
4059                         break;
4060                         case 0xe8:
4061                         logtext = "DIVERSION_ACTIVATED";
4062                         break;
4063                         case 0xe9:
4064                         logtext = "RESERVED_CT_1";
4065                         break;
4066                         case 0xea:
4067                         logtext = "RESERVED_CT_2";
4068                         break;
4069                         case 0xee:
4070                         logtext = "REVERSE_CHARGING";
4071                         break;
4072                         case 0xf9:
4073                         logtext = "REMOTE_HOLD";
4074                         break;
4075                         case 0xfa:
4076                         logtext = "REMOTE_RETRIEVAL";
4077                         break;
4078                         case 0xfb:
4079                         logtext = "CALL_IS_DIVERTING";
4080                         break;
4081                         default:
4082                         SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4083                         logtext = buffer;
4084
4085                 }
4086                 trace_header("NOTIFY", dir);
4087                 if (dir == DIRECTION_OUT)
4088                         add_trace("to", NULL, "CH(%lu)", port_id);
4089                 if (dir == DIRECTION_IN)
4090                         add_trace("from", NULL, "CH(%lu)", port_id);
4091                 if (param->notifyinfo.notify)
4092                         add_trace("indicator", NULL, "%s", logtext);
4093                 if (param->notifyinfo.id[0]) {
4094                         add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4095                         switch(param->notifyinfo.present) {
4096                                 case INFO_PRESENT_RESTRICTED:
4097                                 add_trace("redir'on", "present", "restricted");
4098                                 break;
4099                                 case INFO_PRESENT_ALLOWED:
4100                                 add_trace("redir'on", "present", "allowed");
4101                                 break;
4102                                 default:
4103                                 add_trace("redir'on", "present", "not available");
4104                         }
4105                 }
4106                 if (param->notifyinfo.display[0])
4107                         add_trace("display", NULL, "%s", param->notifyinfo.display);
4108                 end_trace();
4109                 break;
4110
4111                 case MESSAGE_INFORMATION:
4112                 trace_header("INFORMATION", dir);
4113                 if (dir == DIRECTION_OUT)
4114                         add_trace("to", NULL, "CH(%lu)", port_id);
4115                 if (dir == DIRECTION_IN)
4116                         add_trace("from", NULL, "CH(%lu)", port_id);
4117                 if (param->information.id[0])
4118                         add_trace("dialing", NULL, "%s", param->information.id);
4119                 if (param->information.display[0])
4120                         add_trace("display", NULL, "%s", param->information.display);
4121                 if (param->information.sending_complete)
4122                         add_trace("complete", NULL, "true", param->information.sending_complete);
4123                 end_trace();
4124                 break;
4125
4126                 case MESSAGE_FACILITY:
4127                 trace_header("FACILITY", dir);
4128                 if (dir == DIRECTION_OUT)
4129                         add_trace("to", NULL, "CH(%lu)", port_id);
4130                 if (dir == DIRECTION_IN)
4131                         add_trace("from", NULL, "CH(%lu)", port_id);
4132                 end_trace();
4133                 break;
4134
4135                 case MESSAGE_TONE:
4136                 trace_header("TONE", dir);
4137                 if (dir == DIRECTION_OUT)
4138                         add_trace("to", NULL, "CH(%lu)", port_id);
4139                 if (dir == DIRECTION_IN)
4140                         add_trace("from", NULL, "CH(%lu)", port_id);
4141                 if (param->tone.name[0]) {
4142                         add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4143                         add_trace("name", NULL, "%s", param->tone.name);
4144                 } else
4145                         add_trace("off", NULL, NULL);
4146                 end_trace();
4147                 break;
4148
4149                 case MESSAGE_SUSPEND:
4150                 case MESSAGE_RESUME:
4151                 if (message_type == MESSAGE_SUSPEND)
4152                         trace_header("SUSPEND", dir);
4153                 else
4154                         trace_header("RESUME", dir);
4155                 if (dir == DIRECTION_OUT)
4156                         add_trace("to", NULL, "CH(%lu)", port_id);
4157                 if (dir == DIRECTION_IN)
4158                         add_trace("from", NULL, "CH(%lu)", port_id);
4159                 if (param->parkinfo.len)
4160                         add_trace("length", NULL, "%d", param->parkinfo.len);
4161                 end_trace();
4162                 break;
4163
4164 #if 0
4165                 case MESSAGE_BCHANNEL:
4166                 trace_header("BCHANNEL", dir);
4167                 switch(param->bchannel.type) {
4168                         case BCHANNEL_REQUEST:
4169                         add_trace("type", NULL, "request");
4170                         break;
4171                         case BCHANNEL_ASSIGN:
4172                         add_trace("type", NULL, "assign");
4173                         break;
4174                         case BCHANNEL_ASSIGN_ACK:
4175                         add_trace("type", NULL, "assign_ack");
4176                         break;
4177                         case BCHANNEL_REMOVE:
4178                         add_trace("type", NULL, "remove");
4179                         break;
4180                         case BCHANNEL_REMOVE_ACK:
4181                         add_trace("type", NULL, "remove_ack");
4182                         break;
4183                 }
4184                 if (param->bchannel.addr)
4185                         add_trace("address", NULL, "%x", param->bchannel.addr);
4186                 end_trace();
4187                 break;
4188 #endif
4189
4190                 default:
4191                 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4192         }
4193 }
4194
4195 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4196 {
4197         struct lcr_msg *message;
4198
4199         if (!portlist)
4200                 return;
4201         if (!portlist->port_id)
4202                 return;
4203
4204         if (!e_connectedmode) {
4205                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4206                 message->param.disconnectinfo.cause = cause;
4207                 message->param.disconnectinfo.location = location;
4208                 if (display[0])
4209                         SCPY(message->param.disconnectinfo.display, display);
4210                 else
4211                         SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4212         } else {
4213                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4214                 if (display[0])
4215                         SCPY(message->param.notifyinfo.display, display);
4216                 else
4217                         SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4218         }
4219         message_put(message);
4220         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
4221 }
4222