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