Fix: 3PTY bridge must check, if other 3PTY member is mISDN or not
[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, mISDNport->ifport->interface, 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, mISDNport->ifport->interface, 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, mISDNport->ifport->interface, 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
2233         /* signal to call tool */
2234         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);
2235         if (param->notifyinfo.notify) {
2236                 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2237         }
2238
2239         /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2240         if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2241                 case INFO_NOTIFY_REMOTE_HOLD:
2242                 case INFO_NOTIFY_USER_SUSPENDED:
2243                 /* tell call about it */
2244                 if (ea_endpoint->ep_join_id) {
2245                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2246                         message->param.audiopath = 0;
2247                         message_put(message);
2248                 }
2249                 break;
2250
2251                 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2252                 case INFO_NOTIFY_USER_RESUMED:
2253                 /* set volume of rx and tx */
2254                 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2255                 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2256                 if (portlist) {
2257                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2258                         message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2259                         message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2260                         message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2261                         message_put(message);
2262                 }
2263                 /* set current tone */
2264                 if (portlist)
2265                         set_tone(portlist, e_tone);
2266                 /* tell call about it */
2267                 if (ea_endpoint->ep_join_id) {
2268                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2269                         message->param.audiopath = 1;
2270                         message_put(message);
2271                 }
2272                 break;
2273         }
2274
2275         /* notify call if available */
2276         if (ea_endpoint->ep_join_id) {
2277                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2278                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
2279                 message_put(message);
2280         }
2281
2282 }
2283
2284 /* port MESSAGE_PROGRESS */
2285 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2286 {
2287         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2288
2289         struct lcr_msg *message;
2290
2291         /* signal to call tool */
2292         admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2293
2294         /* send progress to call if available */
2295         if (ea_endpoint->ep_join_id) {
2296                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2297                 memcpy(&message->param.progressinfo, &param->progressinfo, sizeof(struct progress_info));
2298                 message_put(message);
2299         }
2300
2301 }
2302
2303 /* port MESSAGE_FACILITY */
2304 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2305 {
2306         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2307
2308         struct lcr_msg *message;
2309
2310         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2311         memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2312         message_put(message);
2313 }
2314
2315 /* port MESSAGE_3PTY */
2316 void EndpointAppPBX::port_3pty(struct port_list *portlist, int message_type, union parameter *param)
2317 {
2318         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2319
2320         struct lcr_msg *message;
2321         int rc;
2322
2323 #if 0
2324         /* bridge for real */
2325         if (param->threepty.begin)
2326                 rc = join_join();
2327         else if (param->threepty.end)
2328                 rc = -ENOTSUP;
2329         else
2330                 return;
2331 #else
2332         /* 3PTY bridge */
2333         if (param->threepty.begin)
2334                 rc = join_3pty();
2335         else if (param->threepty.end)
2336                 rc = split_3pty();
2337         else
2338                 return;
2339 #endif
2340
2341         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_3PTY);
2342         message->param.threepty.begin = param->threepty.begin;
2343         message->param.threepty.end = param->threepty.end;
2344         if (rc < 0)
2345                 message->param.threepty.error = 1;
2346         else
2347                 message->param.threepty.result = 1;
2348         message->param.threepty.invoke_id = param->threepty.invoke_id;
2349         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2350         message_put(message);
2351 }
2352
2353 /* port MESSAGE_SUSPEND */
2354 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2355 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2356 {
2357         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2358
2359         /* epoint is now parked */
2360         ea_endpoint->ep_park = 1;
2361         memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2362         ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2363
2364         /* remove port relation */
2365         ea_endpoint->free_portlist(portlist);
2366 }
2367
2368 /* port MESSAGE_RESUME */
2369 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2370 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2371 {
2372         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2373
2374         /* epoint is now resumed */
2375         ea_endpoint->ep_park = 0;
2376
2377 }
2378
2379 /* port MESSAGE_ENABLEKEYPAD */
2380 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2381 {
2382         struct lcr_msg *message;
2383
2384         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2385
2386         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2387         memcpy(&message->param, param, sizeof(union parameter));
2388         message_put(message);
2389 }
2390
2391
2392 /* port MESSAGE_DISABLE_DEJITTER */
2393 void EndpointAppPBX::port_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
2394 {
2395         struct lcr_msg *message;
2396
2397         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2398
2399         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DISABLE_DEJITTER);
2400         memcpy(&message->param, param, sizeof(union parameter));
2401         message_put(message);
2402 }
2403
2404
2405 /* port sends message to the endpoint
2406  */
2407 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2408 {
2409         struct port_list *portlist;
2410
2411         portlist = ea_endpoint->ep_portlist;
2412         while(portlist) {
2413                 if (port_id == portlist->port_id)
2414                         break;
2415                 portlist = portlist->next;
2416         }
2417         if (!portlist) {
2418                 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);
2419                 return;
2420         }
2421
2422 //      PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2423         switch(message_type) {
2424                 case MESSAGE_TONE_EOF: /* tone is end of file */
2425                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2426                 if (e_action) {
2427                         if (e_action->index == ACTION_VBOX_PLAY) {
2428                                 vbox_message_eof();
2429                         }
2430                         if (e_action->index == ACTION_EFI) {
2431                                 efi_message_eof();
2432                         }
2433                 }
2434                 break;
2435
2436                 case MESSAGE_TONE_COUNTER: /* counter info received */
2437                 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);
2438                 if (e_action)
2439                 if (e_action->index == ACTION_VBOX_PLAY) {
2440                         e_vbox_counter = param->counter.current;
2441                         if (param->counter.max >= 0)
2442                                 e_vbox_counter_max = param->counter.max;
2443                 }
2444                 break;
2445
2446                 /* PORT sends SETUP message */
2447                 case MESSAGE_SETUP:
2448                 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);
2449                 if (e_state!=EPOINT_STATE_IDLE) {
2450                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2451                         break;
2452                 }
2453                 port_setup(portlist, message_type, param);
2454                 break;
2455
2456                 /* PORT sends INFORMATION message */
2457                 case MESSAGE_INFORMATION: /* additional digits received */
2458                 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);
2459                 port_information(portlist, message_type, param);
2460                 break;
2461
2462                 /* PORT sends FACILITY message */
2463                 case MESSAGE_FACILITY:
2464                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2465                 port_facility(portlist, message_type, param);
2466                 break;
2467
2468                 case MESSAGE_3PTY:
2469                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming 3PTY facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2470                 port_3pty(portlist, message_type, param);
2471                 break;
2472
2473                 /* PORT sends DTMF message */
2474                 case MESSAGE_DTMF: /* dtmf digits received */
2475                 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);
2476                 port_dtmf(portlist, message_type, param);
2477                 break;
2478
2479                 /* PORT sends CRYPT message */
2480                 case MESSAGE_CRYPT: /* crypt response received */
2481                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2482                 port_crypt(portlist, message_type, param);
2483                 break;
2484
2485                 /* PORT sends MORE message */
2486                 case MESSAGE_OVERLAP:
2487                 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);
2488                 if (e_state != EPOINT_STATE_OUT_SETUP) {
2489                         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);
2490                         break;
2491                 }
2492                 port_overlap(portlist, message_type, param);
2493                 break;
2494
2495                 /* PORT sends PROCEEDING message */
2496                 case MESSAGE_PROCEEDING: /* port is proceeding */
2497                 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);
2498                 if (e_state!=EPOINT_STATE_OUT_SETUP
2499                  && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2500                         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);
2501                         break;
2502                 }
2503                 port_proceeding(portlist, message_type, param);
2504                 break;
2505
2506                 /* PORT sends ALERTING message */
2507                 case MESSAGE_ALERTING:
2508                 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);
2509                 if (e_state!=EPOINT_STATE_OUT_SETUP
2510                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2511                  && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2512                         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);
2513                         break;
2514                 }
2515                 port_alerting(portlist, message_type, param);
2516                 break;
2517
2518                 /* PORT sends CONNECT message */
2519                 case MESSAGE_CONNECT:
2520                 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);
2521                 if (e_state!=EPOINT_STATE_OUT_SETUP
2522                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2523                  && e_state!=EPOINT_STATE_OUT_PROCEEDING
2524                  && e_state!=EPOINT_STATE_OUT_ALERTING) {
2525                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2526                         break;
2527                 }
2528                 port_connect(portlist, message_type, param);
2529                 break;
2530
2531                 /* PORT sends DISCONNECT message */
2532                 case MESSAGE_DISCONNECT: /* port is disconnected */
2533                 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);
2534                 port_disconnect_release(portlist, message_type, param);
2535                 break;
2536
2537                 /* PORT sends a RELEASE message */
2538                 case MESSAGE_RELEASE: /* port releases */
2539                 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);
2540                 /* portlist is release at port_disconnect_release, thanx Paul */
2541                 port_disconnect_release(portlist, message_type, param);
2542                 break;
2543
2544                 /* PORT sends a TIMEOUT message */
2545                 case MESSAGE_TIMEOUT:
2546                 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);
2547                 port_timeout(portlist, message_type, param);
2548                 break; /* release */
2549
2550                 /* PORT sends a NOTIFY message */
2551                 case MESSAGE_NOTIFY:
2552                 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);
2553                 port_notify(portlist, message_type, param);
2554                 break;
2555
2556                 /* PORT sends a PROGRESS message */
2557                 case MESSAGE_PROGRESS:
2558                 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);
2559                 port_progress(portlist, message_type, param);
2560                 break;
2561
2562                 /* PORT sends a SUSPEND message */
2563                 case MESSAGE_SUSPEND:
2564                 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);
2565                 port_suspend(portlist, message_type, param);
2566                 break; /* suspend */
2567
2568                 /* PORT sends a RESUME message */
2569                 case MESSAGE_RESUME:
2570                 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);
2571                 port_resume(portlist, message_type, param);
2572                 break;
2573
2574 #if 0
2575                 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2576                 /* port assigns bchannel */
2577                 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2578                 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);
2579                 /* only one port is expected to be connected to bchannel */
2580                 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2581                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2582                 break;
2583 #endif
2584
2585                 /* PORT requests DTMF */
2586                 case MESSAGE_ENABLEKEYPAD:
2587                 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);
2588                 port_enablekeypad(portlist, message_type, param);
2589                 break;
2590
2591                 case MESSAGE_DISABLE_DEJITTER:
2592                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming disable dejitter message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2593                 port_disable_dejitter(portlist, message_type, param);
2594                 break;
2595
2596
2597                 default:
2598                 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);
2599         }
2600
2601         /* Note: this endpoint may be destroyed, so we MUST return */
2602 }
2603
2604
2605 /* messages from join
2606  */
2607 /* join MESSAGE_CRYPT */
2608 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2609 {
2610 #ifdef WITH_CRYPT
2611         switch(param->crypt.type) {
2612                 /* message from remote port to "crypt manager" */
2613                 case CU_ACTK_REQ:           /* activate key-exchange */
2614                 case CU_ACTS_REQ:            /* activate shared key */
2615                 case CU_DACT_REQ:          /* deactivate */
2616                 case CU_INFO_REQ:         /* request last info message */
2617                 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2618                 break;
2619
2620                 /* message from "crypt manager" to user */
2621                 case CU_ACTK_CONF:          /* key-echange done */
2622                 case CU_ACTS_CONF:          /* shared key done */
2623                 case CU_DACT_CONF:           /* deactivated */
2624                 case CU_DACT_IND:           /* deactivated */
2625                 case CU_ERROR_IND:         /* receive error message */
2626                 case CU_INFO_IND:         /* receive info message */
2627                 case CU_INFO_CONF:         /* receive info message */
2628                 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2629                 break;
2630
2631                 default:
2632                 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);
2633         }
2634 #endif
2635 }
2636
2637 /* join MESSAGE_INFORMATION */
2638 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2639 {
2640         struct lcr_msg *message;
2641
2642         e_overlap = 1;
2643
2644         while(portlist) {
2645                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2646                 memcpy(&message->param.information, &param->information, sizeof(struct dialing_info));
2647                 message_put(message);
2648                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2649                 portlist = portlist->next;
2650         }
2651 }
2652
2653 /* join MESSAGE_FACILITY */
2654 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2655 {
2656         struct lcr_msg *message;
2657
2658         if (!e_ext.facility && e_ext.number[0]) {
2659                 return;
2660         }
2661
2662         while(portlist) {
2663                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2664                 memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2665                 message_put(message);
2666                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2667                 portlist = portlist->next;
2668         }
2669 }
2670
2671 /* join MESSAGE_MORE */
2672 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2673 {
2674         struct lcr_msg *message;
2675
2676         new_state(EPOINT_STATE_IN_OVERLAP);
2677         
2678         /* own dialtone */
2679         if (e_join_pattern && e_ext.own_setup) {
2680                 /* disconnect audio */
2681                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2682                 message->param.audiopath = 0;
2683                 message_put(message);
2684         }
2685         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2686                         if (e_dialinginfo.id[0])
2687                                 set_tone(portlist, "dialing");
2688                         else
2689                                 set_tone(portlist, "dialtone");
2690                         return;
2691         }
2692         if (e_dialinginfo.id[0]) {
2693                 set_tone(portlist, "dialing");
2694         } else {
2695                 if (e_ext.number[0])
2696                         set_tone(portlist, "dialpbx");
2697                 else
2698                         set_tone(portlist, "dialtone");
2699         }
2700 }
2701
2702 /* join MESSAGE_PROCEEDING */
2703 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2704 {
2705         struct lcr_msg *message;
2706
2707         new_state(EPOINT_STATE_IN_PROCEEDING);
2708
2709         /* own proceeding tone */
2710         if (e_join_pattern) {
2711                 /* connect / disconnect audio */
2712                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2713                 if (e_ext.own_proceeding)
2714                         message->param.audiopath = 0;
2715                 else
2716                         message->param.audiopath = 1;
2717                 message_put(message);
2718         }
2719 //                      UCPY(e_join_tone, "proceeding");
2720         if (portlist) {
2721                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2722                 message_put(message);
2723                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2724         }
2725         set_tone(portlist, "proceeding");
2726 }
2727
2728 /* join MESSAGE_ALERTING */
2729 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2730 {
2731         struct lcr_msg *message;
2732
2733         new_state(EPOINT_STATE_IN_ALERTING);
2734
2735         /* own alerting tone */
2736         if (e_join_pattern) {
2737                 /* connect / disconnect audio */
2738                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2739                 if (e_ext.own_alerting)
2740                         message->param.audiopath = 0;
2741                 else
2742                         message->param.audiopath = 1;
2743                 message_put(message);
2744         }
2745         if (portlist) {
2746                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2747                 message_put(message);
2748                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2749         }
2750         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2751                 set_tone(portlist, "ringing");
2752                 return;
2753         }
2754         if (e_ext.number[0])
2755                 set_tone(portlist, "ringpbx");
2756         else
2757                 set_tone(portlist, "ringing");
2758
2759         if (e_ext.number[0])
2760                 e_dtmf = 1; /* allow dtmf */
2761 }
2762
2763 /* join MESSAGE_CONNECT */
2764 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2765 {
2766         struct lcr_msg *message;
2767         time_t now;
2768
2769         new_state(EPOINT_STATE_CONNECT);
2770 //                      UCPY(e_join_tone, "");
2771 //                      
2772         if (e_ext.number[0])
2773                 e_dtmf = 1; /* allow dtmf */
2774
2775         e_powerdial_on = 0;
2776         unsched_timer(&e_powerdial_timeout);
2777         memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_callerinfo));
2778         if(portlist) {
2779                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2780                 memcpy(&message->param, param, sizeof(union parameter));
2781
2782                 /* screen clip if prefix is required */
2783                 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2784                         SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2785                         SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2786                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2787                 }
2788
2789                 /* use internal caller id */
2790                 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2791                         SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2792                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2793                 }
2794
2795                 /* handle restricted caller ids */
2796                 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);
2797                 /* display callerid if desired for extension */
2798                 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));
2799
2800                 /* use conp, if enabld */
2801 //              if (!e_ext.centrex)
2802 //                      message->param.connectinfo.name[0] = '\0';
2803
2804                 /* send connect */
2805                 message_put(message);
2806                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2807         }
2808         set_tone(portlist, NULL);
2809         e_join_pattern = 0;
2810         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2811         message->param.audiopath = 1;
2812         message_put(message);
2813         time(&now);
2814         e_start = now;
2815 }
2816
2817 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2818 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2819 {
2820         char cause[16];
2821         struct lcr_msg *message;
2822         struct port_list *portlist = NULL;
2823         time_t now;
2824
2825
2826         /* be sure that we are active */
2827         notify_active();
2828         e_tx_state = NOTIFY_STATE_ACTIVE;
2829
2830         /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2831         if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2832                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2833
2834                 /* set time for power dialing */
2835                 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2836                 e_powercount++;
2837
2838                 /* set redial tone */
2839                 if (ea_endpoint->ep_portlist) {
2840                         e_join_pattern = 0;
2841                 }
2842                 set_tone(ea_endpoint->ep_portlist, "redial");
2843                 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);
2844                 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2845                 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2846                         new_state(EPOINT_STATE_IN_PROCEEDING);
2847                         if (ea_endpoint->ep_portlist) {
2848                                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2849                                 message_put(message);
2850                                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2851                         }
2852 /* caused the error, that the first knock sound was not there */
2853 /*                                      set_tone(portlist, "proceeding"); */
2854                 }
2855                 /* send display of powerdialing */
2856                 if (e_ext.display_dialing) {
2857                         portlist = ea_endpoint->ep_portlist;
2858                         while (portlist) {
2859                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2860                                 if (e_powerlimit)
2861                                         SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2862                                 else
2863                                         SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2864                                 message_put(message);
2865                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2866                                 portlist = portlist->next;
2867                         }
2868                 }
2869                 return;
2870         }
2871
2872         /* set stop time */
2873         time(&now);
2874         e_stop = now;
2875
2876         if ((e_state!=EPOINT_STATE_CONNECT
2877           && e_state!=EPOINT_STATE_OUT_DISCONNECT
2878           && e_state!=EPOINT_STATE_IN_OVERLAP
2879           && e_state!=EPOINT_STATE_IN_PROCEEDING
2880           && e_state!=EPOINT_STATE_IN_ALERTING)
2881          || !ea_endpoint->ep_portlist) { /* or no port */
2882                 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2883                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2884                 return; /* must exit here */
2885         }
2886         /* save cause */
2887         if (!e_join_cause) {
2888                 e_join_cause = param->disconnectinfo.cause;
2889                 e_join_location = param->disconnectinfo.location;
2890         }
2891
2892         /* on release we need the audio again! */
2893         if (message_type == MESSAGE_RELEASE) {
2894                 e_join_pattern = 0;
2895                 ea_endpoint->ep_join_id = 0;
2896         }
2897         /* disconnect and select tone */
2898         new_state(EPOINT_STATE_OUT_DISCONNECT);
2899         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2900         /* if own_cause, we must release the join */
2901         if (e_ext.own_cause /* own cause */
2902          || !e_join_pattern) { /* no patterns */
2903                 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);
2904                 if (message_type != MESSAGE_RELEASE)
2905                         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2906                 e_join_pattern = 0;
2907         } else { /* else we enable audio */
2908                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2909                 message->param.audiopath = 1;
2910                 message_put(message);
2911         }
2912         /* send disconnect message */
2913         SCPY(e_tone, cause);
2914         portlist = ea_endpoint->ep_portlist;
2915         while(portlist) {
2916                 set_tone(portlist, cause);
2917                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2918                 portlist = portlist->next;
2919         }
2920 }
2921
2922 /* join MESSAGE_SETUP */
2923 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2924 {
2925         struct lcr_msg *message;
2926 //      struct interface        *interface;
2927
2928         /* if we already in setup state, we just update the dialing with new digits */
2929         if (e_state == EPOINT_STATE_OUT_SETUP
2930          || e_state == EPOINT_STATE_OUT_OVERLAP) {
2931                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
2932                 /* if digits changed, what we have already dialed */
2933                 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
2934                         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);
2935                         /* release all ports */
2936                         while((portlist = ea_endpoint->ep_portlist)) {
2937                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2938                                 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2939                                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2940                                 message_put(message);
2941                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2942                                 ea_endpoint->free_portlist(portlist);
2943                         }
2944
2945                         /* disconnect audio */
2946                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2947                         message->param.audiopath = 0;
2948                         message_put(message);
2949
2950                         /* get dialing info */
2951                         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
2952                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
2953                         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
2954                         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
2955                         new_state(EPOINT_STATE_OUT_OVERLAP);
2956
2957                         /* get time */
2958                         schedule_timer(&e_redial_timeout, 1, 0);
2959                         return;
2960                 }
2961                 /* if we have a pending redial, so we just adjust the dialing number */
2962                 if (e_redial_timeout.active) {
2963                         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);
2964                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
2965                         return;
2966                 }
2967                 if (!ea_endpoint->ep_portlist) {
2968                         PERROR("ERROR: overlap dialing to a NULL port relation\n");
2969                 }
2970                 if (ea_endpoint->ep_portlist->next) {
2971                         PERROR("ERROR: overlap dialing to a port_list port relation\n");
2972                 }
2973                 if (e_state == EPOINT_STATE_OUT_SETUP) {
2974                         /* queue digits */
2975                         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);
2976                         SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2977                         
2978                 } else {
2979                         /* get what we have not dialed yet */
2980                         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));
2981                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2982                         SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2983                         message->param.information.ntype = INFO_NTYPE_UNKNOWN;
2984                         message_put(message);
2985                         logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2986                 }
2987                 /* always store what we have dialed or queued */
2988                 memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
2989                 
2990                 return;
2991         }
2992         if (e_state != EPOINT_STATE_IDLE) {
2993                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2994                 return;
2995         }
2996         /* if an internal extension is dialed, copy that number */
2997         if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
2998                 SCPY(e_ext.number, param->setup.dialinginfo.id);
2999         /* if an internal extension is dialed, get extension's info about caller */
3000         if (e_ext.number[0]) {
3001                 if (!read_extension(&e_ext, e_ext.number)) {
3002                         e_ext.number[0] = '\0';
3003                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3004                 }
3005         }
3006
3007         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3008         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3009         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3010         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3011         memcpy(&e_rtpinfo, &param->setup.rtpinfo, sizeof(e_rtpinfo));
3012
3013         /* process (voice over) data calls */
3014         if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3015                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3016                 memset(&e_capainfo, 0, sizeof(e_capainfo));
3017                 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3018                 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3019                 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3020         }
3021
3022         new_state(EPOINT_STATE_OUT_SETUP);
3023         /* call special setup routine */
3024         out_setup(0);
3025 }
3026
3027 /* join MESSAGE_mISDNSIGNAL */
3028 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3029 {
3030         struct lcr_msg *message;
3031
3032         while(portlist) {
3033                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3034                 memcpy(&message->param, param, sizeof(union parameter));
3035                 message_put(message);
3036                 portlist = portlist->next;
3037         }
3038 }
3039
3040 /* join MESSAGE_BRIDE */
3041 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3042 {
3043         struct lcr_msg *message;
3044
3045         while(portlist) {
3046                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3047                 memcpy(&message->param, param, sizeof(union parameter));
3048                 message_put(message);
3049                 portlist = portlist->next;
3050         }
3051 }
3052
3053 /* join MESSAGE_NOTIFY */
3054 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3055 {
3056         struct lcr_msg *message;
3057         int new_state;
3058
3059         if (param->notifyinfo.notify) {
3060                 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3061 //              /* if notification was generated locally, we turn hold music on/off */ 
3062 //              if (param->notifyinfo.local)
3063 // 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)
3064                 {
3065                         if (e_hold) {
3066                                 /* unhold if */
3067                                 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3068                                         if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3069                                                 while(portlist) {
3070                                                         set_tone(portlist, "");
3071                                                         portlist = portlist->next;
3072                                                 }
3073                                         }
3074                                         portlist = ea_endpoint->ep_portlist;
3075                                         e_hold = 0;
3076                                 }
3077                         } else {
3078                                 /* hold if */
3079                                 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3080                                         while(portlist) {
3081                                                 set_tone(portlist, "hold");
3082                                                 portlist = portlist->next;
3083                                         }
3084                                         portlist = ea_endpoint->ep_portlist;
3085                                         e_hold = 1;
3086                                 }
3087                         }
3088                 }
3089                 /* save new state */
3090                 e_tx_state = new_state;
3091         }
3092
3093         /* notify port(s) about it */
3094         while(portlist) {
3095                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3096                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
3097                 /* handle restricted caller ids */
3098                 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3099                 /* display callerid if desired for extension */
3100                 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));
3101                 message_put(message);
3102                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3103                 portlist = portlist->next;
3104         }
3105 }
3106
3107 /* join MESSAGE_DTMF */
3108 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3109 {
3110         struct lcr_msg *message;
3111
3112         while(portlist) {
3113                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3114                 memcpy(&message->param, param, sizeof(union parameter));
3115                 message_put(message);
3116                 portlist = portlist->next;
3117         }
3118 }
3119
3120 /* join MESSAGE_DISABLE_DEJITTER */
3121 void EndpointAppPBX::join_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
3122 {
3123         struct lcr_msg *message;
3124
3125         while(portlist) {
3126                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISABLE_DEJITTER);
3127                 memcpy(&message->param, param, sizeof(union parameter));
3128                 message_put(message);
3129                 portlist = portlist->next;
3130         }
3131 }
3132
3133 /* JOIN sends messages to the endpoint
3134  */
3135 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3136 {
3137         struct port_list *portlist;
3138         struct lcr_msg *message;
3139
3140         if (!join_id) {
3141                 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3142                 return;
3143         }
3144
3145         portlist = ea_endpoint->ep_portlist;
3146
3147 //      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);
3148         switch(message_type) {
3149                 /* JOIN SENDS TONE message */
3150                 case MESSAGE_TONE:
3151                 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);
3152                 set_tone(portlist, param->tone.name);
3153                 break;
3154
3155                 /* JOIN SENDS CRYPT message */
3156                 case MESSAGE_CRYPT:
3157                 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);
3158                 join_crypt(portlist, message_type, param);
3159                 break;
3160
3161                 /* JOIN sends INFORMATION message */
3162                 case MESSAGE_INFORMATION:
3163                 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);
3164                 join_information(portlist, message_type, param);
3165                 break;
3166
3167                 /* JOIN sends FACILITY message */
3168                 case MESSAGE_FACILITY:
3169                 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);
3170                 join_facility(portlist, message_type, param);
3171                 break;
3172
3173                 /* JOIN sends OVERLAP message */
3174                 case MESSAGE_OVERLAP:
3175                 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);
3176                 if (e_state!=EPOINT_STATE_IN_SETUP
3177                  && e_state!=EPOINT_STATE_IN_OVERLAP) {
3178                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3179                         break;
3180                 }
3181                 join_overlap(portlist, message_type, param);
3182                 break;
3183
3184                 /* JOIN sends PROCEEDING message */
3185                 case MESSAGE_PROCEEDING:
3186                 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);
3187                 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3188                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3189                         break;
3190                 }
3191                 join_proceeding(portlist, message_type, param);
3192                 break;
3193
3194                 /* JOIN sends ALERTING message */
3195                 case MESSAGE_ALERTING:
3196                 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);
3197                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3198                  && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3199                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3200                         break;
3201                 }
3202                 join_alerting(portlist, message_type, param);
3203                 break;
3204
3205                 /* JOIN sends CONNECT message */
3206                 case MESSAGE_CONNECT:
3207                 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);
3208                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3209                  && e_state!=EPOINT_STATE_IN_PROCEEDING
3210                  && e_state!=EPOINT_STATE_IN_ALERTING) {
3211                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3212                         break;
3213                 }
3214                 join_connect(portlist, message_type, param);
3215                 break;
3216
3217                 /* JOIN sends DISCONNECT/RELEASE message */
3218                 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3219                 case MESSAGE_RELEASE: /* JOIN releases */
3220                 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);
3221                 join_disconnect_release(message_type, param);
3222                 break;
3223
3224                 /* JOIN sends SETUP message */
3225                 case MESSAGE_SETUP:
3226                 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);
3227                 join_setup(portlist, message_type, param);
3228                 break;
3229
3230                 /* JOIN sends special mISDNSIGNAL message */
3231                 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3232                 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);
3233                 join_mISDNsignal(portlist, message_type, param);
3234                 break;
3235
3236                 /* JOIN sends bridge message */
3237                 case MESSAGE_BRIDGE: /* bride message to port */
3238                 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);
3239                 join_bridge(portlist, message_type, param);
3240                 break;
3241
3242                 /* JOIN has pattern available */
3243                 case MESSAGE_PATTERN: /* indicating pattern available */
3244                 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);
3245                 if (!e_join_pattern) {
3246                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3247                         e_join_pattern = 1;
3248                         SCPY(e_tone, "");
3249                         while(portlist) {
3250                                 set_tone(portlist, NULL);
3251                                 portlist = portlist->next;
3252                         }
3253                         /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3254                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3255                         message->param.audiopath = 1;
3256                         message_put(message);
3257                 }
3258                 break;
3259
3260                 /* JOIN has no pattern available */
3261                 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3262                 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);
3263                 if (e_join_pattern) {
3264                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3265                         e_join_pattern = 0;
3266                         /* disconnect our audio tx and rx */
3267                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3268                         message->param.audiopath = 0;
3269                         message_put(message);
3270                 }
3271                 break;
3272
3273 #if 0
3274                 /* JOIN (dunno at the moment) */
3275                 case MESSAGE_REMOTE_AUDIO:
3276                 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);
3277                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3278                 message->param.audiopath = param->channel;
3279                 message_put(message);
3280                 break;
3281 #endif
3282
3283                 /* JOIN sends a notify message */
3284                 case MESSAGE_NOTIFY:
3285                 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);
3286                 join_notify(portlist, message_type, param);
3287                 break;
3288
3289                 /* JOIN wants keypad / dtmf */
3290                 case MESSAGE_ENABLEKEYPAD:
3291                 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);
3292                 e_enablekeypad = 1;
3293                 e_dtmf = 1;
3294                 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3295                 end_trace();
3296                 break;
3297
3298                 /* JOIN sends a DTMF message */
3299                 case MESSAGE_DTMF:
3300                 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);
3301                 join_dtmf(portlist, message_type, param);
3302                 break;
3303
3304                 /* JOIN sends a DISABLE_DEJITTER message */
3305                 case MESSAGE_DISABLE_DEJITTER:
3306                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received disable dejitter.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3307                 join_disable_dejitter(portlist, message_type, param);
3308                 break;
3309
3310                 default:
3311                 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);
3312         }
3313 }
3314
3315
3316 /* pick_join will connect the first incoming call found. the endpoint
3317  * will receivce a MESSAGE_CONNECT.
3318  */
3319 int match_list(char *list, char *item)
3320 {
3321         char *end, *next = NULL;
3322
3323         /* no list make matching */
3324         if (!list)
3325                 return(1);
3326
3327         while(42) {
3328                 /* eliminate white spaces */
3329                 while (*list > '\0' && *list <= ' ')
3330                         list++;
3331                 if (*list == ',') {
3332                         list++;
3333                         continue;
3334                 }
3335                 /* if end of list is reached, we return */
3336                 if (list[0] == '\0')
3337                         return(0);
3338                 /* if we have more than one entry (left) */
3339                 if ((end = strchr(list, ',')))
3340                         next = end + 1;
3341                 else
3342                         next = end = strchr(list, '\0');
3343                 while (*(end-1) <= ' ')
3344                         end--;
3345                 /* if string part matches item */
3346                 if (!strncmp(list, item, end-list))
3347                         return(1);
3348                 list = next;
3349         }
3350 }
3351
3352 void EndpointAppPBX::pick_join(char *extensions)
3353 {
3354         struct lcr_msg *message;
3355         struct port_list *portlist;
3356         class Port *port;
3357         class EndpointAppPBX *eapp, *found;
3358         class Join *join;
3359         class JoinPBX *joinpbx;
3360         struct join_relation *relation;
3361         int vbox;
3362
3363         /* find an endpoint that is ringing internally or vbox with higher priority */
3364         vbox = 0;
3365         found = NULL;
3366         eapp = apppbx_first;
3367         while(eapp) {
3368                 if (eapp!=this && ea_endpoint->ep_portlist) {
3369                         portlist = eapp->ea_endpoint->ep_portlist;
3370                         while(portlist) {
3371                                 if ((port = find_port_id(portlist->port_id))) {
3372                                         if (port->p_type == PORT_TYPE_VBOX_OUT) {
3373                                                 if (match_list(extensions, eapp->e_ext.number)) {
3374                                                         found = eapp;
3375                                                         vbox = 1;
3376                                                         break;
3377                                                 }
3378                                         }
3379                                         if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3380                                          && port->p_state==PORT_STATE_OUT_ALERTING)
3381                                                 if (match_list(extensions, eapp->e_ext.number)) {
3382                                                         found = eapp;
3383                                                 }
3384                                 }
3385                                 portlist = portlist->next;
3386                         }
3387                         if (portlist)
3388                                 break;
3389                 }
3390                 eapp = eapp->next;
3391         }
3392
3393         /* if no endpoint found */
3394         if (!found) {
3395                 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);
3396 reject:
3397                 set_tone(ea_endpoint->ep_portlist, "cause_10");
3398                 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3399                 new_state(EPOINT_STATE_OUT_DISCONNECT);
3400                 return;
3401         }
3402         eapp = found;
3403
3404         if (ea_endpoint->ep_join_id) {
3405                 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3406                 goto reject;
3407         }
3408         if (!eapp->ea_endpoint->ep_join_id) {
3409                 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3410                 goto reject;
3411         }
3412         join = find_join_id(eapp->ea_endpoint->ep_join_id);
3413         if (!join) {
3414                 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3415                 goto reject;
3416         }
3417         if (join->j_type != JOIN_TYPE_PBX) {
3418                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3419                 goto reject;
3420         }
3421         joinpbx = (class JoinPBX *)join;
3422         relation = joinpbx->j_relation;
3423         if (!relation) {
3424                 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3425                 goto reject;
3426         }
3427         while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3428                 relation = relation->next;
3429                 if (!relation) {
3430                         PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3431                         goto reject;
3432                 }
3433         }
3434
3435         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3436
3437         if (options.deb & DEBUG_EPOINT) {
3438                 class Join *debug_c = join_first;
3439                 class Endpoint *debug_e = epoint_first;
3440                 class Port *debug_p = port_first;
3441
3442                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3443
3444                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3445                 while(debug_c) {
3446                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3447                         debug_c = debug_c->next;
3448                 }
3449                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3450                 while(debug_e) {
3451                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3452                         debug_e = debug_e->next;
3453                 }
3454                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3455                 while(debug_p) {
3456                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3457                         debug_p = debug_p->next;
3458                 }
3459         }
3460
3461         /* relink join */
3462         ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3463         relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3464         eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3465
3466         /* connnecting our endpoint */
3467         new_state(EPOINT_STATE_CONNECT);
3468         if (e_ext.number[0])
3469                 e_dtmf = 1;
3470         set_tone(ea_endpoint->ep_portlist, NULL);
3471
3472         /* now we send a release to the ringing endpoint */
3473         message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3474         message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3475         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3476         message_put(message);
3477
3478         /* we send a connect to the join with our caller id */
3479         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3480         SCPY(message->param.connectinfo.id, e_callerinfo.id);
3481         message->param.connectinfo.present = e_callerinfo.present;
3482         message->param.connectinfo.screen = e_callerinfo.screen;
3483         message->param.connectinfo.itype = e_callerinfo.itype;
3484         message->param.connectinfo.ntype = e_callerinfo.ntype;
3485         message_put(message);
3486
3487         /* we send a connect to our port with the remote callerid */
3488         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3489         SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3490         message->param.connectinfo.present = eapp->e_callerinfo.present;
3491         message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3492         message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3493         message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3494         /* handle restricted caller ids */
3495         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);
3496         /* display callerid if desired for extension */
3497         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));
3498         message_put(message);
3499
3500         /* we send a connect to the audio path (not for vbox) */
3501         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3502         message->param.audiopath = 1;
3503         message_put(message);
3504
3505         /* beeing paranoid, we make call update */
3506         trigger_work(&joinpbx->j_updatebridge);
3507
3508         if (options.deb & DEBUG_EPOINT) {
3509                 class Join *debug_c = join_first;
3510                 class Endpoint *debug_e = epoint_first;
3511                 class Port *debug_p = port_first;
3512
3513                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3514
3515                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3516                 while(debug_c) {
3517                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3518                         debug_c = debug_c->next;
3519                 }
3520                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3521                 while(debug_e) {
3522                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3523                         debug_e = debug_e->next;
3524                 }
3525                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3526                 while(debug_p) {
3527                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3528                         debug_p = debug_p->next;
3529                 }
3530         }
3531 }
3532
3533
3534 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3535  */
3536 int EndpointAppPBX::join_join(void)
3537 {
3538 #ifdef WITH_MISDN
3539         struct lcr_msg *message;
3540         struct join_relation *add_relation, *remove_relation;
3541         struct join_relation **add_relation_pointer, **remove_relation_pointer;
3542         class Join *our_join, *other_join, *add_join, *remove_join;
3543         class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3544         class EndpointAppPBX *other_eapp, *remove_eapp;
3545         class Port *our_port, *other_port;
3546         class Pdss1 *our_pdss1, *other_pdss1;
3547         class Endpoint *temp_epoint;
3548
3549         /* are we a candidate to join a join? */
3550         our_join = find_join_id(ea_endpoint->ep_join_id);
3551         if (!our_join) {
3552                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3553                 return -1;
3554         }
3555         if (our_join->j_type != JOIN_TYPE_PBX) {
3556                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3557                 return -1;
3558         }
3559         our_joinpbx = (class JoinPBX *)our_join;
3560         if (!ea_endpoint->ep_portlist) {
3561                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3562                 return -1;
3563         }
3564         if (!e_ext.number[0]) {
3565                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3566                 return -1;
3567         }
3568         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3569         if (!our_port) {
3570                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3571                 return -1;
3572         }
3573         if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3574                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3575                 return -1;
3576         }
3577         our_pdss1 = (class Pdss1 *)our_port;
3578
3579         /* find an endpoint that has the same mISDNport/ces that we are on */
3580         other_eapp = apppbx_first;
3581         while(other_eapp) {
3582                 if (other_eapp == this) {
3583                         other_eapp = other_eapp->next;
3584                         continue;
3585                 }
3586                 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);
3587                 if (other_eapp->e_ext.number[0] /* has terminal */
3588                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3589                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3590                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3591                         if (other_port) { /* port still exists */
3592                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3593                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3594                                         other_pdss1 = (class Pdss1 *)other_port;
3595                                         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);
3596                                         if (1 //other_pdss1->p_m_hold /* port is on hold */
3597                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3598                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3599                                                 break;
3600                                 } else {
3601                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3602                                 }
3603                         } else {
3604                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3605                         }
3606                 }
3607                 other_eapp = other_eapp->next;
3608         }
3609         if (!other_eapp) {
3610                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3611                 return -1;
3612         }
3613         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3614
3615         /* if we have the same join */
3616         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3617                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3618                 return -1;
3619         }
3620         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3621         if (!other_join) {
3622                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3623                 return -1;
3624         }
3625         if (other_join->j_type != JOIN_TYPE_PBX) {
3626                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3627                 return -1;
3628         }
3629         other_joinpbx = (class JoinPBX *)other_join;
3630         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3631                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3632                 return -1;
3633         }
3634
3635         /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3636         if (our_pdss1->p_m_hold && !other_pdss1->p_m_hold) {
3637                 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);
3638                 remove_eapp = this;
3639                 remove_join = our_join;
3640                 remove_joinpbx = our_joinpbx;
3641                 add_join = other_join;
3642                 add_joinpbx = other_joinpbx;
3643         } else {
3644                 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);
3645                 remove_eapp = other_eapp;
3646                 remove_join = other_join;
3647                 remove_joinpbx = other_joinpbx;
3648                 add_join = our_join;
3649                 add_joinpbx = our_joinpbx;
3650         }
3651
3652         /* remove relation to endpoint for join on hold */
3653         remove_relation = remove_joinpbx->j_relation;
3654         remove_relation_pointer = &remove_joinpbx->j_relation;
3655         while(remove_relation) {
3656                 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3657                         /* detach other endpoint */
3658                         *remove_relation_pointer = remove_relation->next;
3659                         FREE(remove_relation, sizeof(struct join_relation));
3660                         cmemuse--;
3661                         remove_relation = *remove_relation_pointer;
3662                         remove_eapp->ea_endpoint->ep_join_id = 0;
3663                         continue;
3664                 }
3665
3666                 /* change join/hold pointer of endpoint to the new join */
3667                 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3668                 if (temp_epoint) {
3669                         if (temp_epoint->ep_join_id == remove_join->j_serial)
3670                                 temp_epoint->ep_join_id = add_join->j_serial;
3671                 }
3672
3673                 remove_relation_pointer = &remove_relation->next;
3674                 remove_relation = remove_relation->next;
3675         }
3676         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3677
3678         /* join call relations */
3679         add_relation = add_joinpbx->j_relation;
3680         add_relation_pointer = &add_joinpbx->j_relation;
3681         while(add_relation) {
3682                 add_relation_pointer = &add_relation->next;
3683                 add_relation = add_relation->next;
3684         }
3685         *add_relation_pointer = remove_joinpbx->j_relation;
3686         remove_joinpbx->j_relation = NULL;
3687         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3688
3689         /* release endpoint */
3690         message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3691         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3692         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3693         message_put(message);
3694         
3695         /* if we are not a partyline, we get partyline state from other join */
3696         add_joinpbx->j_partyline += remove_joinpbx->j_partyline; 
3697
3698         /* remove empty join */
3699         delete remove_join;
3700         PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3701
3702         /* mixer must update */
3703         trigger_work(&add_joinpbx->j_updatebridge);
3704
3705         /* we send a retrieve to that endpoint */
3706         // mixer will update the hold-state of the join and send it to the endpoints is changes
3707 #else
3708         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3709 #endif
3710
3711         return 0;
3712 }
3713
3714 int EndpointAppPBX::join_3pty(void)
3715 {
3716 #ifdef WITH_MISDN
3717         class Join *our_join, *other_join;
3718         class JoinPBX *our_joinpbx, *other_joinpbx;
3719         class EndpointAppPBX *other_eapp;
3720         class Port *our_port, *other_port;
3721         class Pdss1 *our_pdss1, *other_pdss1;
3722
3723         /* are we a candidate to join a join? */
3724         our_join = find_join_id(ea_endpoint->ep_join_id);
3725         if (!our_join) {
3726                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3727                 return -1;
3728         }
3729         if (our_join->j_type != JOIN_TYPE_PBX) {
3730                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3731                 return -1;
3732         }
3733         our_joinpbx = (class JoinPBX *)our_join;
3734         if (!ea_endpoint->ep_portlist) {
3735                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3736                 return -1;
3737         }
3738         if (!e_ext.number[0]) {
3739                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3740                 return -1;
3741         }
3742         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3743         if (!our_port) {
3744                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3745                 return -1;
3746         }
3747         if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3748                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3749                 return -1;
3750         }
3751         our_pdss1 = (class Pdss1 *)our_port;
3752
3753         /* find an endpoint that has the same mISDNport/ces that we are on */
3754         other_eapp = apppbx_first;
3755         while(other_eapp) {
3756                 if (other_eapp == this) {
3757                         other_eapp = other_eapp->next;
3758                         continue;
3759                 }
3760                 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);
3761                 if (other_eapp->e_ext.number[0] /* has terminal */
3762                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3763                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3764                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3765                         if (other_port) { /* port still exists */
3766                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3767                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3768                                         other_pdss1 = (class Pdss1 *)other_port;
3769                                         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);
3770                                         if (1 //other_pdss1->p_m_hold /* port is on hold */
3771                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3772                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3773                                                 break;
3774                                 } else {
3775                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3776                                 }
3777                         } else {
3778                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3779                         }
3780                 }
3781                 other_eapp = other_eapp->next;
3782         }
3783         if (!other_eapp) {
3784                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3785                 return -1;
3786         }
3787         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3788
3789         /* if we have the same join */
3790         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3791                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3792                 return -1;
3793         }
3794         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3795         if (!other_join) {
3796                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3797                 return -1;
3798         }
3799         if (other_join->j_type != JOIN_TYPE_PBX) {
3800                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3801                 return -1;
3802         }
3803         other_joinpbx = (class JoinPBX *)other_join;
3804         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3805                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3806                 return -1;
3807         }
3808
3809         if (our_joinpbx->j_3pty) {
3810                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
3811                 return -1;
3812         }
3813         if (other_joinpbx->j_3pty) {
3814                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
3815                 return -1;
3816         }
3817
3818         /* set 3PTY bridge */
3819         other_joinpbx->j_3pty = our_joinpbx->j_serial;
3820         our_joinpbx->j_3pty = other_joinpbx->j_serial;
3821
3822         /* mixer must update */
3823         trigger_work(&our_joinpbx->j_updatebridge);
3824         trigger_work(&other_joinpbx->j_updatebridge);
3825
3826         /* we send a retrieve to that endpoint */
3827         // mixer will update the hold-state of the join and send it to the endpoints is changes
3828 #else
3829         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3830 #endif
3831
3832         return 0;
3833 }
3834
3835 int EndpointAppPBX::split_3pty(void)
3836 {
3837 #ifdef WITH_MISDN
3838         class Join *our_join, *other_join;
3839         class JoinPBX *our_joinpbx, *other_joinpbx;
3840
3841         /* are we a candidate to join a join? */
3842         our_join = find_join_id(ea_endpoint->ep_join_id);
3843         if (!our_join) {
3844                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3845                 return -1;
3846         }
3847         if (our_join->j_type != JOIN_TYPE_PBX) {
3848                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
3849                 return -1;
3850         }
3851         our_joinpbx = (class JoinPBX *)our_join;
3852
3853         if (!our_joinpbx->j_3pty) {
3854                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
3855                 return -1;
3856         }
3857
3858         other_join = find_join_id(our_joinpbx->j_3pty);
3859         if (!other_join) {
3860                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3861                 return -1;
3862         }
3863         if (other_join->j_type != JOIN_TYPE_PBX) {
3864                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
3865                 return -1;
3866         }
3867         other_joinpbx = (class JoinPBX *)other_join;
3868
3869         our_joinpbx->j_3pty = 0;
3870         other_joinpbx->j_3pty = 0;
3871
3872         /* mixer must update */
3873         trigger_work(&our_joinpbx->j_updatebridge);
3874         trigger_work(&other_joinpbx->j_updatebridge);
3875
3876         /* we send a retrieve to that endpoint */
3877         // mixer will update the hold-state of the join and send it to the endpoints is changes
3878 #else
3879         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3880 #endif
3881
3882         return 0;
3883 }
3884
3885 /* check if we have an external call
3886  * this is used to check for encryption ability
3887  */
3888 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3889 {
3890         struct join_relation *relation;
3891         class Join *join;
3892         class JoinPBX *joinpbx;
3893         class Endpoint *epoint;
3894
3895         /* some paranoia check */
3896         if (!ea_endpoint->ep_portlist) {
3897                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3898                 *errstr = "No Call";
3899                 return(1);
3900         }
3901         if (!e_ext.number[0]) {
3902                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3903                 *errstr = "No Call";
3904                 return(1);
3905         }
3906
3907         /* check if we have a join with 2 parties */
3908         join = find_join_id(ea_endpoint->ep_join_id);
3909         if (!join) {
3910                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3911                 *errstr = "No Call";
3912                 return(1);
3913         }
3914         if (join->j_type != JOIN_TYPE_PBX) {
3915                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3916                 *errstr = "No PBX Call";
3917                 return(1);
3918         }
3919         joinpbx = (class JoinPBX *)join;
3920         relation = joinpbx->j_relation;
3921         if (!relation) {
3922                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3923                 *errstr = "No Call";
3924                 return(1);
3925         }
3926         if (!relation->next) {
3927                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3928                 *errstr = "No Call";
3929                 return(1);
3930         }
3931         if (relation->next->next) {
3932                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3933                 *errstr = "Err: Conference";
3934                 return(1);
3935         }
3936         if (relation->epoint_id == ea_endpoint->ep_serial) {
3937                 relation = relation->next;
3938                 if (relation->epoint_id == ea_endpoint->ep_serial) {
3939                         PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3940                         *errstr = "Software Error";
3941                         return(1);
3942                 }
3943         }
3944
3945         /* check remote port for external call */
3946         epoint = find_epoint_id(relation->epoint_id);
3947         if (!epoint) {
3948                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3949                 *errstr = "No Call";
3950                 return(1);
3951         }
3952         if (!epoint->ep_portlist) {
3953                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3954                 *errstr = "No Call";
3955                 return(1);
3956         }
3957         *port = find_port_id(epoint->ep_portlist->port_id);
3958         if (!(*port)) {
3959                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3960                 *errstr = "No Call";
3961                 return(1);
3962         }
3963         if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
3964                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3965                 *errstr = "No Ext Call";
3966                 return(1);
3967         }
3968         if ((*port)->p_state != PORT_STATE_CONNECT) {
3969                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3970                 *errstr = "No Ext Connect";
3971                 return(1);
3972         }
3973         return(0);
3974 }
3975
3976 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3977 {
3978         const char *logtext = "unknown";
3979         char buffer[64];
3980
3981         switch(message_type) {
3982                 case MESSAGE_SETUP:
3983                 trace_header("SETUP", dir);
3984                 if (dir == DIRECTION_OUT)
3985                         add_trace("to", NULL, "CH(%lu)", port_id);
3986                 if (dir == DIRECTION_IN)
3987                         add_trace("from", NULL, "CH(%lu)", port_id);
3988                 if (param->setup.callerinfo.extension[0])
3989                         add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3990                 if (param->setup.callerinfo.interface[0])
3991                         add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
3992                 if (param->setup.dialinginfo.interfaces[0])
3993                         add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
3994                 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3995                 switch(param->setup.callerinfo.present) {
3996                         case INFO_PRESENT_RESTRICTED:
3997                         add_trace("caller id", "present", "restricted");
3998                         break;
3999                         case INFO_PRESENT_ALLOWED:
4000                         add_trace("caller id", "present", "allowed");
4001                         break;
4002                         default:
4003                         add_trace("caller id", "present", "not available");
4004                 }
4005                 if (param->setup.callerinfo.ntype2) {
4006                         add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4007                         switch(param->setup.callerinfo.present) {
4008                                 case INFO_PRESENT_RESTRICTED:
4009                                 add_trace("caller id2", "present", "restricted");
4010                                 break;
4011                                 case INFO_PRESENT_ALLOWED:
4012                                 add_trace("caller id2", "present", "allowed");
4013                                 break;
4014                                 default:
4015                                 add_trace("caller id2", "present", "not available");
4016                         }
4017                 }
4018                 if (param->setup.redirinfo.id[0]) {
4019                         add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4020                         switch(param->setup.redirinfo.present) {
4021                                 case INFO_PRESENT_RESTRICTED:
4022                                 add_trace("redir'ing", "present", "restricted");
4023                                 break;
4024                                 case INFO_PRESENT_ALLOWED:
4025                                 add_trace("redir'ing", "present", "allowed");
4026                                 break;
4027                                 default:
4028                                 add_trace("redir'ing", "present", "not available");
4029                         }
4030                 }
4031                 if (param->setup.dialinginfo.id[0])
4032                         add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4033                 if (param->setup.dialinginfo.keypad[0])
4034                         add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4035                 if (param->setup.dialinginfo.display[0])
4036                         add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4037                 if (param->setup.dialinginfo.sending_complete)
4038                         add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4039                 end_trace();
4040                 break;
4041
4042                 case MESSAGE_OVERLAP:
4043                 trace_header("SETUP ACKNOWLEDGE", dir);
4044                 if (dir == DIRECTION_OUT)
4045                         add_trace("to", NULL, "CH(%lu)", port_id);
4046                 if (dir == DIRECTION_IN)
4047                         add_trace("from", NULL, "CH(%lu)", port_id);
4048                 end_trace();
4049                 break;
4050
4051                 case MESSAGE_PROCEEDING:
4052                 trace_header("PROCEEDING", dir);
4053                 if (dir == DIRECTION_OUT)
4054                         add_trace("to", NULL, "CH(%lu)", port_id);
4055                 if (dir == DIRECTION_IN)
4056                         add_trace("from", NULL, "CH(%lu)", port_id);
4057                 end_trace();
4058                 break;
4059
4060                 case MESSAGE_ALERTING:
4061                 trace_header("ALERTING", dir);
4062                 if (dir == DIRECTION_OUT)
4063                         add_trace("to", NULL, "CH(%lu)", port_id);
4064                 if (dir == DIRECTION_IN)
4065                         add_trace("from", NULL, "CH(%lu)", port_id);
4066                 end_trace();
4067                 break;
4068
4069                 case MESSAGE_CONNECT:
4070                 trace_header("CONNECT", dir);
4071                 if (dir == DIRECTION_OUT)
4072                         add_trace("to", NULL, "CH(%lu)", port_id);
4073                 if (dir == DIRECTION_IN)
4074                         add_trace("from", NULL, "CH(%lu)", port_id);
4075                 if (param->connectinfo.extension[0])
4076                         add_trace("extension", NULL, "%s", param->connectinfo.extension);
4077                 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4078                 switch(param->connectinfo.present) {
4079                         case INFO_PRESENT_RESTRICTED:
4080                         add_trace("connect id", "present", "restricted");
4081                         break;
4082                         case INFO_PRESENT_ALLOWED:
4083                         add_trace("connect id", "present", "allowed");
4084                         break;
4085                         default:
4086                         add_trace("connect id", "present", "not available");
4087                 }
4088                 if (param->connectinfo.display[0])
4089                         add_trace("display", NULL, "%s", param->connectinfo.display);
4090                 end_trace();
4091                 break;
4092
4093                 case MESSAGE_DISCONNECT:
4094                 case MESSAGE_RELEASE:
4095                 if (message_type == MESSAGE_DISCONNECT)
4096                         trace_header("DISCONNECT", dir);
4097                 else
4098                         trace_header("RELEASE", dir);
4099                 if (dir == DIRECTION_OUT)
4100                         add_trace("to", NULL, "CH(%lu)", port_id);
4101                 if (dir == DIRECTION_IN)
4102                         add_trace("from", NULL, "CH(%lu)", port_id);
4103                 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4104                 switch(param->disconnectinfo.location) {
4105                         case LOCATION_USER:
4106                         add_trace("cause", "location", "0-User");
4107                         break;
4108                         case LOCATION_PRIVATE_LOCAL:
4109                         add_trace("cause", "location", "1-Local-PBX");
4110                         break;
4111                         case LOCATION_PUBLIC_LOCAL:
4112                         add_trace("cause", "location", "2-Local-Exchange");
4113                         break;
4114                         case LOCATION_TRANSIT:
4115                         add_trace("cause", "location", "3-Transit");
4116                         break;
4117                         case LOCATION_PUBLIC_REMOTE:
4118                         add_trace("cause", "location", "4-Remote-Exchange");
4119                         break;
4120                         case LOCATION_PRIVATE_REMOTE:
4121                         add_trace("cause", "location", "5-Remote-PBX");
4122                         break;
4123                         case LOCATION_INTERNATIONAL:
4124                         add_trace("cause", "location", "7-International-Exchange");
4125                         break;
4126                         case LOCATION_BEYOND:
4127                         add_trace("cause", "location", "10-Beyond-Interworking");
4128                         break;
4129                         default:
4130                         add_trace("cause", "location", "%d", param->disconnectinfo.location);
4131                 }
4132                 if (param->disconnectinfo.display[0])
4133                         add_trace("display", NULL, "%s", param->disconnectinfo.display);
4134                 end_trace();
4135                 break;
4136
4137                 case MESSAGE_NOTIFY:
4138                 switch(param->notifyinfo.notify) {
4139                         case 0x00:
4140                         logtext = "NULL";
4141                         break;
4142                         case 0x80:
4143                         logtext = "USER_SUSPENDED";
4144                         break;
4145                         case 0x82:
4146                         logtext = "BEARER_SERVICE_CHANGED";
4147                         break;
4148                         case 0x81:
4149                         logtext = "USER_RESUMED";
4150                         break;
4151                         case 0xc2:
4152                         logtext = "CONFERENCE_ESTABLISHED";
4153                         break;
4154                         case 0xc3:
4155                         logtext = "CONFERENCE_DISCONNECTED";
4156                         break;
4157                         case 0xc4:
4158                         logtext = "OTHER_PARTY_ADDED";
4159                         break;
4160                         case 0xc5:
4161                         logtext = "ISOLATED";
4162                         break;
4163                         case 0xc6:
4164                         logtext = "REATTACHED";
4165                         break;
4166                         case 0xc7:
4167                         logtext = "OTHER_PARTY_ISOLATED";
4168                         break;
4169                         case 0xc8:
4170                         logtext = "OTHER_PARTY_REATTACHED";
4171                         break;
4172                         case 0xc9:
4173                         logtext = "OTHER_PARTY_SPLIT";
4174                         break;
4175                         case 0xca:
4176                         logtext = "OTHER_PARTY_DISCONNECTED";
4177                         break;
4178                         case 0xcb:
4179                         logtext = "CONFERENCE_FLOATING";
4180                         break;
4181                         case 0xcc:
4182                         logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4183                         break;
4184                         case 0xcf:
4185                         logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4186                         break;
4187                         case 0xe0:
4188                         logtext = "CALL_IS_A_WAITING_CALL";
4189                         break;
4190                         case 0xe8:
4191                         logtext = "DIVERSION_ACTIVATED";
4192                         break;
4193                         case 0xe9:
4194                         logtext = "RESERVED_CT_1";
4195                         break;
4196                         case 0xea:
4197                         logtext = "RESERVED_CT_2";
4198                         break;
4199                         case 0xee:
4200                         logtext = "REVERSE_CHARGING";
4201                         break;
4202                         case 0xf9:
4203                         logtext = "REMOTE_HOLD";
4204                         break;
4205                         case 0xfa:
4206                         logtext = "REMOTE_RETRIEVAL";
4207                         break;
4208                         case 0xfb:
4209                         logtext = "CALL_IS_DIVERTING";
4210                         break;
4211                         default:
4212                         SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4213                         logtext = buffer;
4214
4215                 }
4216                 trace_header("NOTIFY", dir);
4217                 if (dir == DIRECTION_OUT)
4218                         add_trace("to", NULL, "CH(%lu)", port_id);
4219                 if (dir == DIRECTION_IN)
4220                         add_trace("from", NULL, "CH(%lu)", port_id);
4221                 if (param->notifyinfo.notify)
4222                         add_trace("indicator", NULL, "%s", logtext);
4223                 if (param->notifyinfo.id[0]) {
4224                         add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4225                         switch(param->notifyinfo.present) {
4226                                 case INFO_PRESENT_RESTRICTED:
4227                                 add_trace("redir'on", "present", "restricted");
4228                                 break;
4229                                 case INFO_PRESENT_ALLOWED:
4230                                 add_trace("redir'on", "present", "allowed");
4231                                 break;
4232                                 default:
4233                                 add_trace("redir'on", "present", "not available");
4234                         }
4235                 }
4236                 if (param->notifyinfo.display[0])
4237                         add_trace("display", NULL, "%s", param->notifyinfo.display);
4238                 end_trace();
4239                 break;
4240
4241                 case MESSAGE_PROGRESS:
4242                 switch(param->progressinfo.progress) {
4243                         case 0x01:
4244                         logtext = "Call is not end to end ISDN";
4245                         break;
4246                         case 0x02:
4247                         logtext = "Destination address is non-ISDN";
4248                         break;
4249                         case 0x03:
4250                         logtext = "Origination address is non-ISDN";
4251                         break;
4252                         case 0x04:
4253                         logtext = "Call has returned to the ISDN";
4254                         break;
4255                         case 0x08:
4256                         logtext = "In-band info or pattern available";
4257                         break;
4258                         default:
4259                         SPRINT(buffer, "%d", param->progressinfo.progress);
4260                         logtext = buffer;
4261
4262                 }
4263                 trace_header("PROGRESS", dir);
4264                 if (dir == DIRECTION_OUT)
4265                         add_trace("to", NULL, "CH(%lu)", port_id);
4266                 if (dir == DIRECTION_IN)
4267                         add_trace("from", NULL, "CH(%lu)", port_id);
4268                 add_trace("indicator", NULL, "%s", logtext);
4269                 switch(param->progressinfo.location) {
4270                         case LOCATION_USER:
4271                         add_trace("cause", "location", "0-User");
4272                         break;
4273                         case LOCATION_PRIVATE_LOCAL:
4274                         add_trace("cause", "location", "1-Local-PBX");
4275                         break;
4276                         case LOCATION_PUBLIC_LOCAL:
4277                         add_trace("cause", "location", "2-Local-Exchange");
4278                         break;
4279                         case LOCATION_TRANSIT:
4280                         add_trace("cause", "location", "3-Transit");
4281                         break;
4282                         case LOCATION_PUBLIC_REMOTE:
4283                         add_trace("cause", "location", "4-Remote-Exchange");
4284                         break;
4285                         case LOCATION_PRIVATE_REMOTE:
4286                         add_trace("cause", "location", "5-Remote-PBX");
4287                         break;
4288                         case LOCATION_INTERNATIONAL:
4289                         add_trace("cause", "location", "7-International-Exchange");
4290                         break;
4291                         case LOCATION_BEYOND:
4292                         add_trace("cause", "location", "10-Beyond-Interworking");
4293                         break;
4294                         default:
4295                         add_trace("cause", "location", "%d", param->progressinfo.location);
4296                 }
4297                 end_trace();
4298                 break;
4299
4300                 case MESSAGE_INFORMATION:
4301                 trace_header("INFORMATION", dir);
4302                 if (dir == DIRECTION_OUT)
4303                         add_trace("to", NULL, "CH(%lu)", port_id);
4304                 if (dir == DIRECTION_IN)
4305                         add_trace("from", NULL, "CH(%lu)", port_id);
4306                 if (param->information.id[0])
4307                         add_trace("dialing", NULL, "%s", param->information.id);
4308                 if (param->information.display[0])
4309                         add_trace("display", NULL, "%s", param->information.display);
4310                 if (param->information.sending_complete)
4311                         add_trace("complete", NULL, "true", param->information.sending_complete);
4312                 end_trace();
4313                 break;
4314
4315                 case MESSAGE_FACILITY:
4316                 trace_header("FACILITY", dir);
4317                 if (dir == DIRECTION_OUT)
4318                         add_trace("to", NULL, "CH(%lu)", port_id);
4319                 if (dir == DIRECTION_IN)
4320                         add_trace("from", NULL, "CH(%lu)", port_id);
4321                 end_trace();
4322                 break;
4323
4324                 case MESSAGE_TONE:
4325                 trace_header("TONE", dir);
4326                 if (dir == DIRECTION_OUT)
4327                         add_trace("to", NULL, "CH(%lu)", port_id);
4328                 if (dir == DIRECTION_IN)
4329                         add_trace("from", NULL, "CH(%lu)", port_id);
4330                 if (param->tone.name[0]) {
4331                         add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4332                         add_trace("name", NULL, "%s", param->tone.name);
4333                 } else
4334                         add_trace("off", NULL, NULL);
4335                 end_trace();
4336                 break;
4337
4338                 case MESSAGE_SUSPEND:
4339                 case MESSAGE_RESUME:
4340                 if (message_type == MESSAGE_SUSPEND)
4341                         trace_header("SUSPEND", dir);
4342                 else
4343                         trace_header("RESUME", dir);
4344                 if (dir == DIRECTION_OUT)
4345                         add_trace("to", NULL, "CH(%lu)", port_id);
4346                 if (dir == DIRECTION_IN)
4347                         add_trace("from", NULL, "CH(%lu)", port_id);
4348                 if (param->parkinfo.len)
4349                         add_trace("length", NULL, "%d", param->parkinfo.len);
4350                 end_trace();
4351                 break;
4352
4353 #if 0
4354                 case MESSAGE_BCHANNEL:
4355                 trace_header("BCHANNEL", dir);
4356                 switch(param->bchannel.type) {
4357                         case BCHANNEL_REQUEST:
4358                         add_trace("type", NULL, "request");
4359                         break;
4360                         case BCHANNEL_ASSIGN:
4361                         add_trace("type", NULL, "assign");
4362                         break;
4363                         case BCHANNEL_ASSIGN_ACK:
4364                         add_trace("type", NULL, "assign_ack");
4365                         break;
4366                         case BCHANNEL_REMOVE:
4367                         add_trace("type", NULL, "remove");
4368                         break;
4369                         case BCHANNEL_REMOVE_ACK:
4370                         add_trace("type", NULL, "remove_ack");
4371                         break;
4372                 }
4373                 if (param->bchannel.addr)
4374                         add_trace("address", NULL, "%x", param->bchannel.addr);
4375                 end_trace();
4376                 break;
4377 #endif
4378
4379                 case MESSAGE_3PTY:
4380                 if (param->threepty.begin)
4381                         trace_header("Begin3PTY", dir);
4382                 if (param->threepty.end)
4383                         trace_header("End3PTY", dir);
4384                 if (param->threepty.invoke)
4385                         add_trace("action", NULL, "invoke");
4386                 if (param->threepty.result)
4387                         add_trace("action", NULL, "result");
4388                 if (param->threepty.error)
4389                         add_trace("action", NULL, "error");
4390                 add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id);
4391                 end_trace();
4392                 break;
4393
4394                 case MESSAGE_DISABLE_DEJITTER:
4395                 trace_header("DISBALE_DEJITTER", dir);
4396                 if (param->queue)
4397                         add_trace("queue", NULL, "%d", param->queue);
4398                 end_trace();
4399                 break;
4400
4401                 default:
4402                 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4403         }
4404 }
4405
4406 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4407 {
4408         struct lcr_msg *message;
4409
4410         if (!portlist)
4411                 return;
4412         if (!portlist->port_id)
4413                 return;
4414
4415         if (!e_connectedmode) {
4416                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4417                 message->param.disconnectinfo.cause = cause;
4418                 message->param.disconnectinfo.location = location;
4419                 if (display[0])
4420                         SCPY(message->param.disconnectinfo.display, display);
4421                 else
4422                         SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4423         } else {
4424                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4425                 if (display[0])
4426                         SCPY(message->param.notifyinfo.display, display);
4427                 else
4428                         SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4429         }
4430         message_put(message);
4431         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
4432 }
4433