perform default/timeout action when sending is complete
[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
3395         /* find an endpoint that is ringing internally or vbox with higher priority */
3396         found = NULL;
3397         eapp = apppbx_first;
3398         while(eapp) {
3399                 if (eapp!=this && ea_endpoint->ep_portlist) {
3400                         portlist = eapp->ea_endpoint->ep_portlist;
3401                         while(portlist) {
3402                                 if ((port = find_port_id(portlist->port_id))) {
3403                                         if (port->p_type == PORT_TYPE_VBOX_OUT) {
3404                                                 if (match_list(extensions, eapp->e_ext.number)) {
3405                                                         found = eapp;
3406                                                         break;
3407                                                 }
3408                                         }
3409                                         if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3410                                          && port->p_state==PORT_STATE_OUT_ALERTING)
3411                                                 if (match_list(extensions, eapp->e_ext.number)) {
3412                                                         found = eapp;
3413                                                 }
3414                                 }
3415                                 portlist = portlist->next;
3416                         }
3417                         if (portlist)
3418                                 break;
3419                 }
3420                 eapp = eapp->next;
3421         }
3422
3423         /* if no endpoint found */
3424         if (!found) {
3425                 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);
3426 reject:
3427                 set_tone(ea_endpoint->ep_portlist, "cause_10");
3428                 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3429                 new_state(EPOINT_STATE_OUT_DISCONNECT);
3430                 return;
3431         }
3432         eapp = found;
3433
3434         if (ea_endpoint->ep_join_id) {
3435                 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3436                 goto reject;
3437         }
3438         if (!eapp->ea_endpoint->ep_join_id) {
3439                 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3440                 goto reject;
3441         }
3442         join = find_join_id(eapp->ea_endpoint->ep_join_id);
3443         if (!join) {
3444                 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3445                 goto reject;
3446         }
3447         if (join->j_type != JOIN_TYPE_PBX) {
3448                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3449                 goto reject;
3450         }
3451         joinpbx = (class JoinPBX *)join;
3452         relation = joinpbx->j_relation;
3453         if (!relation) {
3454                 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3455                 goto reject;
3456         }
3457         while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3458                 relation = relation->next;
3459                 if (!relation) {
3460                         PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3461                         goto reject;
3462                 }
3463         }
3464
3465         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3466
3467         if (options.deb & DEBUG_EPOINT) {
3468                 class Join *debug_c = join_first;
3469                 class Endpoint *debug_e = epoint_first;
3470                 class Port *debug_p = port_first;
3471
3472                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3473
3474                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3475                 while(debug_c) {
3476                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3477                         debug_c = debug_c->next;
3478                 }
3479                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3480                 while(debug_e) {
3481                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3482                         debug_e = debug_e->next;
3483                 }
3484                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3485                 while(debug_p) {
3486                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3487                         debug_p = debug_p->next;
3488                 }
3489         }
3490
3491         /* relink join */
3492         ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3493         relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3494         eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3495
3496         /* connnecting our endpoint */
3497         new_state(EPOINT_STATE_CONNECT);
3498         if (e_ext.number[0])
3499                 e_dtmf = 1;
3500         set_tone(ea_endpoint->ep_portlist, NULL);
3501
3502         /* now we send a release to the ringing endpoint */
3503         message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3504         message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3505         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3506         message_put(message);
3507
3508         /* we send a connect to the join with our caller id */
3509         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3510         SCPY(message->param.connectinfo.id, e_callerinfo.id);
3511         message->param.connectinfo.present = e_callerinfo.present;
3512         message->param.connectinfo.screen = e_callerinfo.screen;
3513         message->param.connectinfo.itype = e_callerinfo.itype;
3514         message->param.connectinfo.ntype = e_callerinfo.ntype;
3515         message_put(message);
3516
3517         /* we send a connect to our port with the remote callerid */
3518         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3519         SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3520         message->param.connectinfo.present = eapp->e_callerinfo.present;
3521         message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3522         message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3523         message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3524         /* handle restricted caller ids */
3525         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);
3526         /* display callerid if desired for extension */
3527         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));
3528         message_put(message);
3529
3530         /* we send a connect to the audio path (not for vbox) */
3531         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3532         message->param.audiopath = 1;
3533         message_put(message);
3534
3535         /* beeing paranoid, we make call update */
3536         trigger_work(&joinpbx->j_updatebridge);
3537
3538         if (options.deb & DEBUG_EPOINT) {
3539                 class Join *debug_c = join_first;
3540                 class Endpoint *debug_e = epoint_first;
3541                 class Port *debug_p = port_first;
3542
3543                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3544
3545                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3546                 while(debug_c) {
3547                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3548                         debug_c = debug_c->next;
3549                 }
3550                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3551                 while(debug_e) {
3552                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3553                         debug_e = debug_e->next;
3554                 }
3555                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3556                 while(debug_p) {
3557                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3558                         debug_p = debug_p->next;
3559                 }
3560         }
3561 }
3562
3563
3564 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3565  */
3566 int EndpointAppPBX::join_join_dss1(void)
3567 {
3568 #ifdef WITH_MISDN
3569         struct lcr_msg *message;
3570         struct join_relation *add_relation, *remove_relation;
3571         struct join_relation **add_relation_pointer, **remove_relation_pointer;
3572         class Join *our_join, *other_join, *add_join, *remove_join;
3573         class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3574         class EndpointAppPBX *other_eapp, *remove_eapp;
3575         class Port *our_port, *other_port;
3576         class Pdss1 *our_pdss1, *other_pdss1;
3577         class Endpoint *temp_epoint;
3578
3579         /* are we a candidate to join a join? */
3580         our_join = find_join_id(ea_endpoint->ep_join_id);
3581         if (!our_join) {
3582                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3583                 return -1;
3584         }
3585         if (our_join->j_type != JOIN_TYPE_PBX) {
3586                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3587                 return -1;
3588         }
3589         our_joinpbx = (class JoinPBX *)our_join;
3590         if (!ea_endpoint->ep_portlist) {
3591                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3592                 return -1;
3593         }
3594         if (!e_ext.number[0]) {
3595                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3596                 return -1;
3597         }
3598         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3599         if (!our_port) {
3600                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3601                 return -1;
3602         }
3603         if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3604                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3605                 return -1;
3606         }
3607         our_pdss1 = (class Pdss1 *)our_port;
3608
3609         /* find an endpoint that has the same mISDNport/ces that we are on */
3610         other_eapp = apppbx_first;
3611         while(other_eapp) {
3612                 if (other_eapp == this) {
3613                         other_eapp = other_eapp->next;
3614                         continue;
3615                 }
3616                 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);
3617                 if (other_eapp->e_ext.number[0] /* has terminal */
3618                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3619                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3620                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3621                         if (other_port) { /* port still exists */
3622                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3623                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3624                                         other_pdss1 = (class Pdss1 *)other_port;
3625                                         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);
3626                                         if (1 //other_pdss1->p_m_hold /* port is on hold */
3627                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3628                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3629                                                 break;
3630                                 } else {
3631                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3632                                 }
3633                         } else {
3634                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3635                         }
3636                 }
3637                 other_eapp = other_eapp->next;
3638         }
3639         if (!other_eapp) {
3640                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3641                 return -1;
3642         }
3643         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3644
3645         /* if we have the same join */
3646         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3647                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3648                 return -1;
3649         }
3650         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3651         if (!other_join) {
3652                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3653                 return -1;
3654         }
3655         if (other_join->j_type != JOIN_TYPE_PBX) {
3656                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3657                 return -1;
3658         }
3659         other_joinpbx = (class JoinPBX *)other_join;
3660         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3661                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3662                 return -1;
3663         }
3664
3665         /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3666         if (our_pdss1->p_m_hold && !other_pdss1->p_m_hold) {
3667                 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);
3668                 remove_eapp = this;
3669                 remove_join = our_join;
3670                 remove_joinpbx = our_joinpbx;
3671                 add_join = other_join;
3672                 add_joinpbx = other_joinpbx;
3673         } else {
3674                 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);
3675                 remove_eapp = other_eapp;
3676                 remove_join = other_join;
3677                 remove_joinpbx = other_joinpbx;
3678                 add_join = our_join;
3679                 add_joinpbx = our_joinpbx;
3680         }
3681
3682         /* remove relation to endpoint for join on hold */
3683         remove_relation = remove_joinpbx->j_relation;
3684         remove_relation_pointer = &remove_joinpbx->j_relation;
3685         while(remove_relation) {
3686                 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3687                         /* detach other endpoint */
3688                         *remove_relation_pointer = remove_relation->next;
3689                         FREE(remove_relation, sizeof(struct join_relation));
3690                         cmemuse--;
3691                         remove_relation = *remove_relation_pointer;
3692                         remove_eapp->ea_endpoint->ep_join_id = 0;
3693                         continue;
3694                 }
3695
3696                 /* change join/hold pointer of endpoint to the new join */
3697                 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3698                 if (temp_epoint) {
3699                         if (temp_epoint->ep_join_id == remove_join->j_serial)
3700                                 temp_epoint->ep_join_id = add_join->j_serial;
3701                 }
3702
3703                 remove_relation_pointer = &remove_relation->next;
3704                 remove_relation = remove_relation->next;
3705         }
3706         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3707
3708         /* join call relations */
3709         add_relation = add_joinpbx->j_relation;
3710         add_relation_pointer = &add_joinpbx->j_relation;
3711         while(add_relation) {
3712                 add_relation_pointer = &add_relation->next;
3713                 add_relation = add_relation->next;
3714         }
3715         *add_relation_pointer = remove_joinpbx->j_relation;
3716         remove_joinpbx->j_relation = NULL;
3717         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3718
3719         /* release endpoint */
3720         message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3721         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3722         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3723         message_put(message);
3724         
3725         /* if we are not a partyline, we get partyline state from other join */
3726         add_joinpbx->j_partyline += remove_joinpbx->j_partyline; 
3727
3728         /* remove empty join */
3729         delete remove_join;
3730         PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3731
3732         /* mixer must update */
3733         trigger_work(&add_joinpbx->j_updatebridge);
3734
3735         /* we send a retrieve to that endpoint */
3736         // mixer will update the hold-state of the join and send it to the endpoints is changes
3737 #else
3738         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3739 #endif
3740
3741         return 0;
3742 }
3743
3744 /* join calls (look for a join that is on hold (same fxs interface/terminal))
3745  */
3746 int EndpointAppPBX::join_join_fxs(void)
3747 {
3748 #ifdef WITH_MISDN
3749         struct lcr_msg *message;
3750         struct join_relation *add_relation, *remove_relation;
3751         struct join_relation **add_relation_pointer, **remove_relation_pointer;
3752         class Join *our_join, *other_join, *add_join, *remove_join;
3753         class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3754         class EndpointAppPBX *other_eapp, *remove_eapp;
3755         class Port *our_port, *other_port;
3756         class Pfxs *our_fxs, *other_fxs;
3757         class Endpoint *temp_epoint;
3758
3759         /* are we a candidate to join a join? */
3760         our_join = find_join_id(ea_endpoint->ep_join_id);
3761         if (!our_join) {
3762                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3763                 return -1;
3764         }
3765         if (our_join->j_type != JOIN_TYPE_PBX) {
3766                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3767                 return -1;
3768         }
3769         our_joinpbx = (class JoinPBX *)our_join;
3770         if (!ea_endpoint->ep_portlist) {
3771                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3772                 return -1;
3773         }
3774         if (!e_ext.number[0]) {
3775                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3776                 return -1;
3777         }
3778         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3779         if (!our_port) {
3780                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3781                 return -1;
3782         }
3783         if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
3784                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not fxs.\n", ea_endpoint->ep_serial);
3785                 return -1;
3786         }
3787         our_fxs = (class Pfxs *)our_port;
3788
3789         /* find an endpoint that has the same mISDNport that we are on */
3790         other_eapp = apppbx_first;
3791         while(other_eapp) {
3792                 if (other_eapp == this) {
3793                         other_eapp = other_eapp->next;
3794                         continue;
3795                 }
3796                 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);
3797                 if (other_eapp->e_ext.number[0] /* has terminal */
3798                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3799                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3800                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3801                         if (other_port) { /* port still exists */
3802                                 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
3803                                  || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is FXS */
3804                                         other_fxs = (class Pfxs *)other_port;
3805                                         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);
3806                                         if (1 //other_fxs->p_m_hold /* port is on hold */
3807                                          && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
3808                                                 break;
3809                                 } else {
3810                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3811                                 }
3812                         } else {
3813                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3814                         }
3815                 }
3816                 other_eapp = other_eapp->next;
3817         }
3818         if (!other_eapp) {
3819                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
3820                 return -1;
3821         }
3822         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3823
3824         /* if we have the same join */
3825         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3826                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3827                 return -1;
3828         }
3829         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3830         if (!other_join) {
3831                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3832                 return -1;
3833         }
3834         if (other_join->j_type != JOIN_TYPE_PBX) {
3835                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3836                 return -1;
3837         }
3838         other_joinpbx = (class JoinPBX *)other_join;
3839         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3840                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3841                 return -1;
3842         }
3843
3844         /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3845         if (our_fxs->p_m_hold && !other_fxs->p_m_hold) {
3846                 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);
3847                 remove_eapp = this;
3848                 remove_join = our_join;
3849                 remove_joinpbx = our_joinpbx;
3850                 add_join = other_join;
3851                 add_joinpbx = other_joinpbx;
3852         } else {
3853                 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);
3854                 remove_eapp = other_eapp;
3855                 remove_join = other_join;
3856                 remove_joinpbx = other_joinpbx;
3857                 add_join = our_join;
3858                 add_joinpbx = our_joinpbx;
3859         }
3860
3861         /* remove relation to endpoint for join on hold */
3862         remove_relation = remove_joinpbx->j_relation;
3863         remove_relation_pointer = &remove_joinpbx->j_relation;
3864         while(remove_relation) {
3865                 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3866                         /* detach other endpoint */
3867                         *remove_relation_pointer = remove_relation->next;
3868                         FREE(remove_relation, sizeof(struct join_relation));
3869                         cmemuse--;
3870                         remove_relation = *remove_relation_pointer;
3871                         remove_eapp->ea_endpoint->ep_join_id = 0;
3872                         continue;
3873                 }
3874
3875                 /* change join/hold pointer of endpoint to the new join */
3876                 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3877                 if (temp_epoint) {
3878                         if (temp_epoint->ep_join_id == remove_join->j_serial)
3879                                 temp_epoint->ep_join_id = add_join->j_serial;
3880                 }
3881
3882                 remove_relation_pointer = &remove_relation->next;
3883                 remove_relation = remove_relation->next;
3884         }
3885         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3886
3887         /* join call relations */
3888         add_relation = add_joinpbx->j_relation;
3889         add_relation_pointer = &add_joinpbx->j_relation;
3890         while(add_relation) {
3891                 add_relation_pointer = &add_relation->next;
3892                 add_relation = add_relation->next;
3893         }
3894         *add_relation_pointer = remove_joinpbx->j_relation;
3895         remove_joinpbx->j_relation = NULL;
3896         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3897
3898         /* release endpoint */
3899         message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3900         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3901         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3902         message_put(message);
3903         
3904         /* if we are not a partyline, we get partyline state from other join */
3905         add_joinpbx->j_partyline += remove_joinpbx->j_partyline; 
3906
3907         /* remove empty join */
3908         delete remove_join;
3909         PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3910
3911         /* mixer must update */
3912         trigger_work(&add_joinpbx->j_updatebridge);
3913
3914         /* we send a retrieve to that endpoint */
3915         // mixer will update the hold-state of the join and send it to the endpoints is changes
3916 #else
3917         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3918 #endif
3919
3920         return 0;
3921 }
3922
3923 int EndpointAppPBX::join_3pty_dss1(void)
3924 {
3925 #ifdef WITH_MISDN
3926         class Join *our_join, *other_join;
3927         class JoinPBX *our_joinpbx, *other_joinpbx;
3928         class EndpointAppPBX *other_eapp;
3929         class Port *our_port, *other_port;
3930         class Pdss1 *our_pdss1, *other_pdss1;
3931
3932         /* are we a candidate to join a join? */
3933         our_join = find_join_id(ea_endpoint->ep_join_id);
3934         if (!our_join) {
3935                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3936                 return -1;
3937         }
3938         if (our_join->j_type != JOIN_TYPE_PBX) {
3939                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3940                 return -1;
3941         }
3942         our_joinpbx = (class JoinPBX *)our_join;
3943         if (!ea_endpoint->ep_portlist) {
3944                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3945                 return -1;
3946         }
3947         if (!e_ext.number[0]) {
3948                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3949                 return -1;
3950         }
3951         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3952         if (!our_port) {
3953                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3954                 return -1;
3955         }
3956         if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3957                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3958                 return -1;
3959         }
3960         our_pdss1 = (class Pdss1 *)our_port;
3961
3962         /* find an endpoint that has the same mISDNport/ces that we are on */
3963         other_eapp = apppbx_first;
3964         while(other_eapp) {
3965                 if (other_eapp == this) {
3966                         other_eapp = other_eapp->next;
3967                         continue;
3968                 }
3969                 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);
3970                 if (other_eapp->e_ext.number[0] /* has terminal */
3971                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3972                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3973                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3974                         if (other_port) { /* port still exists */
3975                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3976                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3977                                         other_pdss1 = (class Pdss1 *)other_port;
3978                                         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);
3979                                         if (1 //other_pdss1->p_m_hold /* port is on hold */
3980                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3981                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3982                                                 break;
3983                                 } else {
3984                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3985                                 }
3986                         } else {
3987                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3988                         }
3989                 }
3990                 other_eapp = other_eapp->next;
3991         }
3992         if (!other_eapp) {
3993                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3994                 return -1;
3995         }
3996         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3997
3998         /* if we have the same join */
3999         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4000                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4001                 return -1;
4002         }
4003         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4004         if (!other_join) {
4005                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4006                 return -1;
4007         }
4008         if (other_join->j_type != JOIN_TYPE_PBX) {
4009                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4010                 return -1;
4011         }
4012         other_joinpbx = (class JoinPBX *)other_join;
4013         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4014                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4015                 return -1;
4016         }
4017
4018         if (our_joinpbx->j_3pty) {
4019                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4020                 return -1;
4021         }
4022         if (other_joinpbx->j_3pty) {
4023                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4024                 return -1;
4025         }
4026
4027         /* set 3PTY bridge */
4028         other_joinpbx->j_3pty = our_joinpbx->j_serial;
4029         our_joinpbx->j_3pty = other_joinpbx->j_serial;
4030
4031         /* mixer must update */
4032         trigger_work(&our_joinpbx->j_updatebridge);
4033         trigger_work(&other_joinpbx->j_updatebridge);
4034
4035         /* we send a retrieve to that endpoint */
4036         // mixer will update the hold-state of the join and send it to the endpoints is changes
4037 #else
4038         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4039 #endif
4040
4041         return 0;
4042 }
4043
4044 int EndpointAppPBX::join_3pty_fxs(void)
4045 {
4046 #ifdef WITH_MISDN
4047         class Join *our_join, *other_join;
4048         class JoinPBX *our_joinpbx, *other_joinpbx;
4049         class EndpointAppPBX *other_eapp;
4050         class Port *our_port, *other_port;
4051         class Pfxs *our_fxs, *other_fxs;
4052
4053         /* are we a candidate to join a join? */
4054         our_join = find_join_id(ea_endpoint->ep_join_id);
4055         if (!our_join) {
4056                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4057                 return -1;
4058         }
4059         if (our_join->j_type != JOIN_TYPE_PBX) {
4060                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4061                 return -1;
4062         }
4063         our_joinpbx = (class JoinPBX *)our_join;
4064         if (!ea_endpoint->ep_portlist) {
4065                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4066                 return -1;
4067         }
4068         if (!e_ext.number[0]) {
4069                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4070                 return -1;
4071         }
4072         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4073         if (!our_port) {
4074                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4075                 return -1;
4076         }
4077         if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
4078                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not FXS pots.\n", ea_endpoint->ep_serial);
4079                 return -1;
4080         }
4081         our_fxs = (class Pfxs *)our_port;
4082
4083         /* find an endpoint that has the same mISDNport that we are on */
4084         other_eapp = apppbx_first;
4085         while(other_eapp) {
4086                 if (other_eapp == this) {
4087                         other_eapp = other_eapp->next;
4088                         continue;
4089                 }
4090                 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);
4091                 if (other_eapp->e_ext.number[0] /* has terminal */
4092                  && other_eapp->ea_endpoint->ep_portlist /* has port */
4093                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4094                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4095                         if (other_port) { /* port still exists */
4096                                 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4097                                  || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is isdn nt-mode */
4098                                         other_fxs = (class Pfxs *)other_port;
4099                                         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);
4100                                         if (1 //other_fxs->p_m_hold /* port is on hold */
4101                                          && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
4102                                                 break;
4103                                 } else {
4104                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4105                                 }
4106                         } else {
4107                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4108                         }
4109                 }
4110                 other_eapp = other_eapp->next;
4111         }
4112         if (!other_eapp) {
4113                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4114                 return -1;
4115         }
4116         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4117
4118         /* if we have the same join */
4119         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4120                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4121                 return -1;
4122         }
4123         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4124         if (!other_join) {
4125                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4126                 return -1;
4127         }
4128         if (other_join->j_type != JOIN_TYPE_PBX) {
4129                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4130                 return -1;
4131         }
4132         other_joinpbx = (class JoinPBX *)other_join;
4133         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4134                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4135                 return -1;
4136         }
4137
4138         if (our_joinpbx->j_3pty) {
4139                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4140                 return -1;
4141         }
4142         if (other_joinpbx->j_3pty) {
4143                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4144                 return -1;
4145         }
4146
4147         /* set 3PTY bridge */
4148         other_joinpbx->j_3pty = our_joinpbx->j_serial;
4149         our_joinpbx->j_3pty = other_joinpbx->j_serial;
4150
4151         /* mixer must update */
4152         trigger_work(&our_joinpbx->j_updatebridge);
4153         trigger_work(&other_joinpbx->j_updatebridge);
4154
4155         /* we send a retrieve to that endpoint */
4156         // mixer will update the hold-state of the join and send it to the endpoints is changes
4157 #else
4158         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4159 #endif
4160
4161         return 0;
4162 }
4163
4164 int EndpointAppPBX::split_3pty(void)
4165 {
4166 #ifdef WITH_MISDN
4167         class Join *our_join, *other_join;
4168         class JoinPBX *our_joinpbx, *other_joinpbx;
4169
4170         /* are we a candidate to join a join? */
4171         our_join = find_join_id(ea_endpoint->ep_join_id);
4172         if (!our_join) {
4173                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4174                 return -1;
4175         }
4176         if (our_join->j_type != JOIN_TYPE_PBX) {
4177                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4178                 return -1;
4179         }
4180         our_joinpbx = (class JoinPBX *)our_join;
4181
4182         if (!our_joinpbx->j_3pty) {
4183                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
4184                 return -1;
4185         }
4186
4187         other_join = find_join_id(our_joinpbx->j_3pty);
4188         if (!other_join) {
4189                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4190                 return -1;
4191         }
4192         if (other_join->j_type != JOIN_TYPE_PBX) {
4193                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4194                 return -1;
4195         }
4196         other_joinpbx = (class JoinPBX *)other_join;
4197
4198         our_joinpbx->j_3pty = 0;
4199         other_joinpbx->j_3pty = 0;
4200
4201         /* mixer must update */
4202         trigger_work(&our_joinpbx->j_updatebridge);
4203         trigger_work(&other_joinpbx->j_updatebridge);
4204
4205         /* we send a retrieve to that endpoint */
4206         // mixer will update the hold-state of the join and send it to the endpoints is changes
4207 #else
4208         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4209 #endif
4210
4211         return 0;
4212 }
4213
4214 /* check if we have an external call
4215  * this is used to check for encryption ability
4216  */
4217 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
4218 {
4219         struct join_relation *relation;
4220         class Join *join;
4221         class JoinPBX *joinpbx;
4222         class Endpoint *epoint;
4223
4224         /* some paranoia check */
4225         if (!ea_endpoint->ep_portlist) {
4226                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4227                 *errstr = "No Call";
4228                 return(1);
4229         }
4230         if (!e_ext.number[0]) {
4231                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4232                 *errstr = "No Call";
4233                 return(1);
4234         }
4235
4236         /* check if we have a join with 2 parties */
4237         join = find_join_id(ea_endpoint->ep_join_id);
4238         if (!join) {
4239                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
4240                 *errstr = "No Call";
4241                 return(1);
4242         }
4243         if (join->j_type != JOIN_TYPE_PBX) {
4244                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4245                 *errstr = "No PBX Call";
4246                 return(1);
4247         }
4248         joinpbx = (class JoinPBX *)join;
4249         relation = joinpbx->j_relation;
4250         if (!relation) {
4251                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4252                 *errstr = "No Call";
4253                 return(1);
4254         }
4255         if (!relation->next) {
4256                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4257                 *errstr = "No Call";
4258                 return(1);
4259         }
4260         if (relation->next->next) {
4261                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4262                 *errstr = "Err: Conference";
4263                 return(1);
4264         }
4265         if (relation->epoint_id == ea_endpoint->ep_serial) {
4266                 relation = relation->next;
4267                 if (relation->epoint_id == ea_endpoint->ep_serial) {
4268                         PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4269                         *errstr = "Software Error";
4270                         return(1);
4271                 }
4272         }
4273
4274         /* check remote port for external call */
4275         epoint = find_epoint_id(relation->epoint_id);
4276         if (!epoint) {
4277                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4278                 *errstr = "No Call";
4279                 return(1);
4280         }
4281         if (!epoint->ep_portlist) {
4282                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4283                 *errstr = "No Call";
4284                 return(1);
4285         }
4286         *port = find_port_id(epoint->ep_portlist->port_id);
4287         if (!(*port)) {
4288                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4289                 *errstr = "No Call";
4290                 return(1);
4291         }
4292         if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4293                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4294                 *errstr = "No Ext Call";
4295                 return(1);
4296         }
4297         if ((*port)->p_state != PORT_STATE_CONNECT) {
4298                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4299                 *errstr = "No Ext Connect";
4300                 return(1);
4301         }
4302         return(0);
4303 }
4304
4305 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4306 {
4307         const char *logtext = "unknown";
4308         char buffer[64];
4309
4310         switch(message_type) {
4311                 case MESSAGE_SETUP:
4312                 trace_header("SETUP", dir);
4313                 if (dir == DIRECTION_OUT)
4314                         add_trace("to", NULL, "CH(%lu)", port_id);
4315                 if (dir == DIRECTION_IN)
4316                         add_trace("from", NULL, "CH(%lu)", port_id);
4317                 if (param->setup.callerinfo.extension[0])
4318                         add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4319                 if (param->setup.callerinfo.interface[0])
4320                         add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
4321                 if (param->setup.dialinginfo.interfaces[0])
4322                         add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
4323                 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4324                 switch(param->setup.callerinfo.present) {
4325                         case INFO_PRESENT_RESTRICTED:
4326                         add_trace("caller id", "present", "restricted");
4327                         break;
4328                         case INFO_PRESENT_ALLOWED:
4329                         add_trace("caller id", "present", "allowed");
4330                         break;
4331                         default:
4332                         add_trace("caller id", "present", "not available");
4333                 }
4334                 if (param->setup.callerinfo.ntype2) {
4335                         add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4336                         switch(param->setup.callerinfo.present) {
4337                                 case INFO_PRESENT_RESTRICTED:
4338                                 add_trace("caller id2", "present", "restricted");
4339                                 break;
4340                                 case INFO_PRESENT_ALLOWED:
4341                                 add_trace("caller id2", "present", "allowed");
4342                                 break;
4343                                 default:
4344                                 add_trace("caller id2", "present", "not available");
4345                         }
4346                 }
4347                 if (param->setup.redirinfo.id[0]) {
4348                         add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4349                         switch(param->setup.redirinfo.present) {
4350                                 case INFO_PRESENT_RESTRICTED:
4351                                 add_trace("redir'ing", "present", "restricted");
4352                                 break;
4353                                 case INFO_PRESENT_ALLOWED:
4354                                 add_trace("redir'ing", "present", "allowed");
4355                                 break;
4356                                 default:
4357                                 add_trace("redir'ing", "present", "not available");
4358                         }
4359                 }
4360                 if (param->setup.dialinginfo.id[0])
4361                         add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4362                 if (param->setup.dialinginfo.keypad[0])
4363                         add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4364                 if (param->setup.dialinginfo.display[0])
4365                         add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4366                 if (param->setup.dialinginfo.sending_complete)
4367                         add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4368                 end_trace();
4369                 break;
4370
4371                 case MESSAGE_OVERLAP:
4372                 trace_header("SETUP ACKNOWLEDGE", dir);
4373                 if (dir == DIRECTION_OUT)
4374                         add_trace("to", NULL, "CH(%lu)", port_id);
4375                 if (dir == DIRECTION_IN)
4376                         add_trace("from", NULL, "CH(%lu)", port_id);
4377                 end_trace();
4378                 break;
4379
4380                 case MESSAGE_PROCEEDING:
4381                 trace_header("PROCEEDING", dir);
4382                 if (dir == DIRECTION_OUT)
4383                         add_trace("to", NULL, "CH(%lu)", port_id);
4384                 if (dir == DIRECTION_IN)
4385                         add_trace("from", NULL, "CH(%lu)", port_id);
4386                 end_trace();
4387                 break;
4388
4389                 case MESSAGE_ALERTING:
4390                 trace_header("ALERTING", dir);
4391                 if (dir == DIRECTION_OUT)
4392                         add_trace("to", NULL, "CH(%lu)", port_id);
4393                 if (dir == DIRECTION_IN)
4394                         add_trace("from", NULL, "CH(%lu)", port_id);
4395                 end_trace();
4396                 break;
4397
4398                 case MESSAGE_CONNECT:
4399                 trace_header("CONNECT", dir);
4400                 if (dir == DIRECTION_OUT)
4401                         add_trace("to", NULL, "CH(%lu)", port_id);
4402                 if (dir == DIRECTION_IN)
4403                         add_trace("from", NULL, "CH(%lu)", port_id);
4404                 if (param->connectinfo.extension[0])
4405                         add_trace("extension", NULL, "%s", param->connectinfo.extension);
4406                 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4407                 switch(param->connectinfo.present) {
4408                         case INFO_PRESENT_RESTRICTED:
4409                         add_trace("connect id", "present", "restricted");
4410                         break;
4411                         case INFO_PRESENT_ALLOWED:
4412                         add_trace("connect id", "present", "allowed");
4413                         break;
4414                         default:
4415                         add_trace("connect id", "present", "not available");
4416                 }
4417                 if (param->connectinfo.display[0])
4418                         add_trace("display", NULL, "%s", param->connectinfo.display);
4419                 end_trace();
4420                 break;
4421
4422                 case MESSAGE_DISCONNECT:
4423                 case MESSAGE_RELEASE:
4424                 if (message_type == MESSAGE_DISCONNECT)
4425                         trace_header("DISCONNECT", dir);
4426                 else
4427                         trace_header("RELEASE", dir);
4428                 if (dir == DIRECTION_OUT)
4429                         add_trace("to", NULL, "CH(%lu)", port_id);
4430                 if (dir == DIRECTION_IN)
4431                         add_trace("from", NULL, "CH(%lu)", port_id);
4432                 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4433                 switch(param->disconnectinfo.location) {
4434                         case LOCATION_USER:
4435                         add_trace("cause", "location", "0-User");
4436                         break;
4437                         case LOCATION_PRIVATE_LOCAL:
4438                         add_trace("cause", "location", "1-Local-PBX");
4439                         break;
4440                         case LOCATION_PUBLIC_LOCAL:
4441                         add_trace("cause", "location", "2-Local-Exchange");
4442                         break;
4443                         case LOCATION_TRANSIT:
4444                         add_trace("cause", "location", "3-Transit");
4445                         break;
4446                         case LOCATION_PUBLIC_REMOTE:
4447                         add_trace("cause", "location", "4-Remote-Exchange");
4448                         break;
4449                         case LOCATION_PRIVATE_REMOTE:
4450                         add_trace("cause", "location", "5-Remote-PBX");
4451                         break;
4452                         case LOCATION_INTERNATIONAL:
4453                         add_trace("cause", "location", "7-International-Exchange");
4454                         break;
4455                         case LOCATION_BEYOND:
4456                         add_trace("cause", "location", "10-Beyond-Interworking");
4457                         break;
4458                         default:
4459                         add_trace("cause", "location", "%d", param->disconnectinfo.location);
4460                 }
4461                 if (param->disconnectinfo.display[0])
4462                         add_trace("display", NULL, "%s", param->disconnectinfo.display);
4463                 end_trace();
4464                 break;
4465
4466                 case MESSAGE_NOTIFY:
4467                 switch(param->notifyinfo.notify) {
4468                         case 0x00:
4469                         logtext = "NULL";
4470                         break;
4471                         case 0x80:
4472                         logtext = "USER_SUSPENDED";
4473                         break;
4474                         case 0x82:
4475                         logtext = "BEARER_SERVICE_CHANGED";
4476                         break;
4477                         case 0x81:
4478                         logtext = "USER_RESUMED";
4479                         break;
4480                         case 0xc2:
4481                         logtext = "CONFERENCE_ESTABLISHED";
4482                         break;
4483                         case 0xc3:
4484                         logtext = "CONFERENCE_DISCONNECTED";
4485                         break;
4486                         case 0xc4:
4487                         logtext = "OTHER_PARTY_ADDED";
4488                         break;
4489                         case 0xc5:
4490                         logtext = "ISOLATED";
4491                         break;
4492                         case 0xc6:
4493                         logtext = "REATTACHED";
4494                         break;
4495                         case 0xc7:
4496                         logtext = "OTHER_PARTY_ISOLATED";
4497                         break;
4498                         case 0xc8:
4499                         logtext = "OTHER_PARTY_REATTACHED";
4500                         break;
4501                         case 0xc9:
4502                         logtext = "OTHER_PARTY_SPLIT";
4503                         break;
4504                         case 0xca:
4505                         logtext = "OTHER_PARTY_DISCONNECTED";
4506                         break;
4507                         case 0xcb:
4508                         logtext = "CONFERENCE_FLOATING";
4509                         break;
4510                         case 0xcc:
4511                         logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4512                         break;
4513                         case 0xcf:
4514                         logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4515                         break;
4516                         case 0xe0:
4517                         logtext = "CALL_IS_A_WAITING_CALL";
4518                         break;
4519                         case 0xe8:
4520                         logtext = "DIVERSION_ACTIVATED";
4521                         break;
4522                         case 0xe9:
4523                         logtext = "RESERVED_CT_1";
4524                         break;
4525                         case 0xea:
4526                         logtext = "RESERVED_CT_2";
4527                         break;
4528                         case 0xee:
4529                         logtext = "REVERSE_CHARGING";
4530                         break;
4531                         case 0xf9:
4532                         logtext = "REMOTE_HOLD";
4533                         break;
4534                         case 0xfa:
4535                         logtext = "REMOTE_RETRIEVAL";
4536                         break;
4537                         case 0xfb:
4538                         logtext = "CALL_IS_DIVERTING";
4539                         break;
4540                         default:
4541                         SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4542                         logtext = buffer;
4543
4544                 }
4545                 trace_header("NOTIFY", dir);
4546                 if (dir == DIRECTION_OUT)
4547                         add_trace("to", NULL, "CH(%lu)", port_id);
4548                 if (dir == DIRECTION_IN)
4549                         add_trace("from", NULL, "CH(%lu)", port_id);
4550                 if (param->notifyinfo.notify)
4551                         add_trace("indicator", NULL, "%s", logtext);
4552                 if (param->notifyinfo.id[0]) {
4553                         add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4554                         switch(param->notifyinfo.present) {
4555                                 case INFO_PRESENT_RESTRICTED:
4556                                 add_trace("redir'on", "present", "restricted");
4557                                 break;
4558                                 case INFO_PRESENT_ALLOWED:
4559                                 add_trace("redir'on", "present", "allowed");
4560                                 break;
4561                                 default:
4562                                 add_trace("redir'on", "present", "not available");
4563                         }
4564                 }
4565                 if (param->notifyinfo.display[0])
4566                         add_trace("display", NULL, "%s", param->notifyinfo.display);
4567                 end_trace();
4568                 break;
4569
4570                 case MESSAGE_PROGRESS:
4571                 switch(param->progressinfo.progress) {
4572                         case 0x01:
4573                         logtext = "Call is not end to end ISDN";
4574                         break;
4575                         case 0x02:
4576                         logtext = "Destination address is non-ISDN";
4577                         break;
4578                         case 0x03:
4579                         logtext = "Origination address is non-ISDN";
4580                         break;
4581                         case 0x04:
4582                         logtext = "Call has returned to the ISDN";
4583                         break;
4584                         case 0x08:
4585                         logtext = "In-band info or pattern available";
4586                         break;
4587                         default:
4588                         SPRINT(buffer, "%d", param->progressinfo.progress);
4589                         logtext = buffer;
4590
4591                 }
4592                 trace_header("PROGRESS", dir);
4593                 if (dir == DIRECTION_OUT)
4594                         add_trace("to", NULL, "CH(%lu)", port_id);
4595                 if (dir == DIRECTION_IN)
4596                         add_trace("from", NULL, "CH(%lu)", port_id);
4597                 add_trace("indicator", NULL, "%s", logtext);
4598                 switch(param->progressinfo.location) {
4599                         case LOCATION_USER:
4600                         add_trace("cause", "location", "0-User");
4601                         break;
4602                         case LOCATION_PRIVATE_LOCAL:
4603                         add_trace("cause", "location", "1-Local-PBX");
4604                         break;
4605                         case LOCATION_PUBLIC_LOCAL:
4606                         add_trace("cause", "location", "2-Local-Exchange");
4607                         break;
4608                         case LOCATION_TRANSIT:
4609                         add_trace("cause", "location", "3-Transit");
4610                         break;
4611                         case LOCATION_PUBLIC_REMOTE:
4612                         add_trace("cause", "location", "4-Remote-Exchange");
4613                         break;
4614                         case LOCATION_PRIVATE_REMOTE:
4615                         add_trace("cause", "location", "5-Remote-PBX");
4616                         break;
4617                         case LOCATION_INTERNATIONAL:
4618                         add_trace("cause", "location", "7-International-Exchange");
4619                         break;
4620                         case LOCATION_BEYOND:
4621                         add_trace("cause", "location", "10-Beyond-Interworking");
4622                         break;
4623                         default:
4624                         add_trace("cause", "location", "%d", param->progressinfo.location);
4625                 }
4626                 end_trace();
4627                 break;
4628
4629                 case MESSAGE_INFORMATION:
4630                 trace_header("INFORMATION", dir);
4631                 if (dir == DIRECTION_OUT)
4632                         add_trace("to", NULL, "CH(%lu)", port_id);
4633                 if (dir == DIRECTION_IN)
4634                         add_trace("from", NULL, "CH(%lu)", port_id);
4635                 if (param->information.id[0])
4636                         add_trace("dialing", NULL, "%s", param->information.id);
4637                 if (param->information.display[0])
4638                         add_trace("display", NULL, "%s", param->information.display);
4639                 if (param->information.sending_complete)
4640                         add_trace("complete", NULL, "true", param->information.sending_complete);
4641                 end_trace();
4642                 break;
4643
4644                 case MESSAGE_FACILITY:
4645                 trace_header("FACILITY", dir);
4646                 if (dir == DIRECTION_OUT)
4647                         add_trace("to", NULL, "CH(%lu)", port_id);
4648                 if (dir == DIRECTION_IN)
4649                         add_trace("from", NULL, "CH(%lu)", port_id);
4650                 end_trace();
4651                 break;
4652
4653                 case MESSAGE_TONE:
4654                 trace_header("TONE", dir);
4655                 if (dir == DIRECTION_OUT)
4656                         add_trace("to", NULL, "CH(%lu)", port_id);
4657                 if (dir == DIRECTION_IN)
4658                         add_trace("from", NULL, "CH(%lu)", port_id);
4659                 if (param->tone.name[0]) {
4660                         add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4661                         add_trace("name", NULL, "%s", param->tone.name);
4662                 } else
4663                         add_trace("off", NULL, NULL);
4664                 end_trace();
4665                 break;
4666
4667                 case MESSAGE_SUSPEND:
4668                 case MESSAGE_RESUME:
4669                 if (message_type == MESSAGE_SUSPEND)
4670                         trace_header("SUSPEND", dir);
4671                 else
4672                         trace_header("RESUME", dir);
4673                 if (dir == DIRECTION_OUT)
4674                         add_trace("to", NULL, "CH(%lu)", port_id);
4675                 if (dir == DIRECTION_IN)
4676                         add_trace("from", NULL, "CH(%lu)", port_id);
4677                 if (param->parkinfo.len)
4678                         add_trace("length", NULL, "%d", param->parkinfo.len);
4679                 end_trace();
4680                 break;
4681
4682 #if 0
4683                 case MESSAGE_BCHANNEL:
4684                 trace_header("BCHANNEL", dir);
4685                 switch(param->bchannel.type) {
4686                         case BCHANNEL_REQUEST:
4687                         add_trace("type", NULL, "request");
4688                         break;
4689                         case BCHANNEL_ASSIGN:
4690                         add_trace("type", NULL, "assign");
4691                         break;
4692                         case BCHANNEL_ASSIGN_ACK:
4693                         add_trace("type", NULL, "assign_ack");
4694                         break;
4695                         case BCHANNEL_REMOVE:
4696                         add_trace("type", NULL, "remove");
4697                         break;
4698                         case BCHANNEL_REMOVE_ACK:
4699                         add_trace("type", NULL, "remove_ack");
4700                         break;
4701                 }
4702                 if (param->bchannel.addr)
4703                         add_trace("address", NULL, "%x", param->bchannel.addr);
4704                 end_trace();
4705                 break;
4706 #endif
4707
4708                 case MESSAGE_3PTY:
4709                 if (param->threepty.begin)
4710                         trace_header("Begin3PTY", dir);
4711                 if (param->threepty.end)
4712                         trace_header("End3PTY", dir);
4713                 if (param->threepty.invoke)
4714                         add_trace("action", NULL, "invoke");
4715                 if (param->threepty.result)
4716                         add_trace("action", NULL, "result");
4717                 if (param->threepty.error)
4718                         add_trace("action", NULL, "error");
4719                 add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id);
4720                 end_trace();
4721                 break;
4722
4723                 case MESSAGE_TRANSFER:
4724                 trace_header("TRANSFER", dir);
4725                 end_trace();
4726                 break;
4727
4728                 case MESSAGE_DISABLE_DEJITTER:
4729                 trace_header("DISBALE_DEJITTER", dir);
4730                 if (param->queue)
4731                         add_trace("queue", NULL, "%d", param->queue);
4732                 end_trace();
4733                 break;
4734
4735                 default:
4736                 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4737         }
4738 }
4739
4740 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4741 {
4742         struct lcr_msg *message;
4743
4744         if (!portlist)
4745                 return;
4746         if (!portlist->port_id)
4747                 return;
4748
4749         if (!e_connectedmode) {
4750                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4751                 message->param.disconnectinfo.cause = cause;
4752                 message->param.disconnectinfo.location = location;
4753                 if (display[0])
4754                         SCPY(message->param.disconnectinfo.display, display);
4755                 else
4756                         SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4757         } else {
4758                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4759                 if (display[0])
4760                         SCPY(message->param.notifyinfo.display, display);
4761                 else
4762                         SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4763         }
4764         message_put(message);
4765         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
4766 }
4767