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