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