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