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