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