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