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