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