Fixed output problems of error messages while parsing options.conf / gsm.conf.
[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 'external' 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(void)
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
900                 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
901                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
902                         p = "vbox";
903                         goto vbox_only;
904                 }
905
906                 /* string from unconditional call forward (cfu) */
907                 p = e_ext.cfu;
908                 if (*p) {
909                         /* present to forwarded party */
910                         if (e_ext.anon_ignore && e_callerinfo.id[0]) {
911                                 e_callerinfo.present = INFO_PRESENT_ALLOWED;
912                         }
913                         if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
914                                 goto cfu_only;
915                 }
916
917                 /* string from busy call forward (cfb) */
918                 p = e_ext.cfb;
919                 if (*p) {
920                         class EndpointAppPBX *checkapp = apppbx_first;
921                         while(checkapp) {
922                                 if (checkapp != this) { /* any other endpoint except our own */
923                                         if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
924                                                 /* present to forwarded party */
925                                                 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
926                                                         e_callerinfo.present = INFO_PRESENT_ALLOWED;
927                                                 }
928                                                 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
929                                                         goto cfb_only;
930                                         }
931                                 }
932                                 checkapp = checkapp->next;
933                         }
934                 }
935
936                 /* string from no-response call forward (cfnr) */
937                 p = e_ext.cfnr;
938                 if (*p) {
939                         /* when cfnr is done, out_setup() will setup the call */
940                         if (e_cfnr_call_timeout.active) {
941                                 /* present to forwarded party */
942                                 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
943                                         e_callerinfo.present = INFO_PRESENT_ALLOWED;
944                                 }
945                                 goto cfnr_only;
946                         }
947                         if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
948                                 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
949                                 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
950                                 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);
951                         }
952                 }
953
954                 /* call to all internal interfaces */
955                 p = e_ext.interfaces;
956                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
957                 while(*p) {
958                         ifname[0] = '\0';
959                         while(*p!=',' && *p!='\0')
960                                 if (*p > ' ')
961                                         SCCAT(ifname, *p++);
962                         if (*p == ',')
963                                 p++;
964                         /* found interface */
965                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
966                         /* hunt for mISDNport and create Port */
967                         mISDNport = hunt_port(ifname, &channel);
968                         if (!mISDNport) {
969                                 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
970                                 add_trace("interface", NULL, "%s", ifname);
971                                 end_trace();
972                                 continue;
973                         }
974                         /* creating INTERNAL port */
975                         SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
976 #ifdef WITH_SS5
977                         if (mISDNport->ss5)
978                                 port = ss5_hunt_line(mISDNport);
979                         else
980 #endif
981                         if (!mISDNport->gsm)
982                                 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);
983                         else
984 #ifdef WITH_GSM
985                                 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
986 #else
987                                 port = NULL;
988 #endif
989                         if (!port)
990                                 FATAL("No memory for Port instance\n");
991                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
992                         memset(&dialinginfo, 0, sizeof(dialinginfo));
993                         SCPY(dialinginfo.id, e_dialinginfo.id);
994                         dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
995                         dialinginfo.ntype = e_dialinginfo.ntype;
996                         /* create port_list relation */
997                         portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
998                         if (!portlist) {
999                                 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1000                                 delete port;
1001                                 goto check_anycall_intern;
1002                         }
1003                         /* directory.list */
1004                         if (e_callerinfo.id[0] && e_ext.display_name) {
1005                                 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1006                                 if (dirname)
1007                                         SCPY(e_callerinfo.name, dirname);
1008                         }
1009 //                      dss1 = (class Pdss1 *)port;
1010                         /* message */
1011 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1012                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1013                         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1014                         memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1015                         memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1016                         memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1017 //terminal                      SCPY(message->param.setup.from_terminal, e_ext.number);
1018 //terminal                      if (e_dialinginfo.id)
1019 //terminal                              SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1020                         /* handle restricted caller ids */
1021                         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);
1022                         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);
1023                         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);
1024                         /* display callerid if desired for extension */
1025                         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));
1026 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1027                         /* use cnip, if enabld */
1028         //              if (!e_ext.centrex)
1029         //                      message->param.setup.callerinfo.name[0] = '\0';
1030                         /* screen clip if prefix is required */
1031                         if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1032                                 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1033                                 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1034                                 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1035                         }
1036                         if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1037                                 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1038                                 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1039                                 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1040                         }
1041                         /* use internal caller id */
1042                         if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1043                                 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1044                                 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1045                                 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1046                         }
1047                         message_put(message);
1048                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1049                         anycall = 1;
1050                 }
1051
1052                 /* string from parallel call forward (cfp) */
1053                 p = e_ext.cfp;
1054                 if (*p) {
1055                         if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1056                                 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1057                                 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1058                         }
1059                 }
1060
1061                 vbox_only: /* entry point for answering machine only */
1062                 cfu_only: /* entry point for cfu */
1063                 cfb_only: /* entry point for cfb */
1064                 cfnr_only: /* entry point for cfnr */
1065                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1066 //              i=0;
1067                 while(*p) {
1068                         earlyb = 0;
1069                         /* only if vbox should be dialed, and terminal is given */
1070                         if (!strcmp(p, "vbox") && e_ext.number[0]) {
1071                                 /* go to the end of p */
1072                                 p += strlen(p);
1073
1074                                 /* answering vbox call */
1075                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1076                                 /* alloc port */
1077                                 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1078                                         FATAL("No memory for VBOX Port instance\n");
1079                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1080                                 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1081                         } else {
1082                                 cfp[0] = '\0';
1083                                 while(*p!=',' && *p!='\0')
1084                                         SCCAT(cfp, *p++);
1085                                 if (*p == ',')
1086                                         p++;
1087                                 /* external call */
1088                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1089                                 /* hunt for mISDNport and create Port */
1090                                 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1091                                 if (mISDNport) {
1092                                         /* creating EXTERNAL port*/
1093                                         SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1094 #ifdef WITH_SS5
1095                                         if (mISDNport->ss5)
1096                                                 port = ss5_hunt_line(mISDNport);
1097                                         else
1098 #endif
1099                                                 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);
1100                                         if (!port)
1101                                                 FATAL("No memory for Port instance\n");
1102                                         earlyb = mISDNport->earlyb;
1103                                 } else {
1104                                         port = NULL;
1105                                         trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1106                                         add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1107                                         end_trace();
1108                                 }
1109                         }
1110                         if (!port) {
1111                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1112                                 goto check_anycall_intern;
1113                         }
1114                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1115                         memset(&dialinginfo, 0, sizeof(dialinginfo));
1116                         SCPY(dialinginfo.id, cfp);
1117                         dialinginfo.itype = INFO_ITYPE_ISDN;
1118                         dialinginfo.ntype = e_dialinginfo.ntype;
1119                         portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1120                         if (!portlist) {
1121                                 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1122                                 delete port;
1123                                 goto check_anycall_intern;
1124                         }
1125 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1126                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1127                         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1128                         memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1129                         memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1130                         /* if clip is hidden */
1131                         if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1132                                 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1133                                 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1134                                 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1135                                 message->param.setup.callerinfo.present = e_ext.callerid_present;
1136                                 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1137                         }
1138                         memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1139 //terminal                      SCPY(message->param.setup.from_terminal, e_ext.number);
1140 //terminal                      if (e_dialinginfo.id)
1141 //terminal                              SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1142                                 /* handle restricted caller ids */
1143                         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);
1144                         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);
1145                         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);
1146                         /* display callerid if desired for extension */
1147                         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));
1148                         message_put(message);
1149                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1150                         anycall = 1;
1151                 }
1152
1153                 check_anycall_intern:
1154                 /* now we have all ports created */
1155                 if (!anycall) {
1156                         trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1157                         end_trace();
1158                         if (!ea_endpoint->ep_join_id)
1159                                 break;
1160                         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1161                         return; /* must exit here */
1162                 }
1163                 break;
1164
1165                 /* *********************** external call */
1166                 default:
1167                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1168                 /* call to extenal interfaces */
1169                 if (e_dialinginfo.keypad[0])
1170                         p = e_dialinginfo.keypad;
1171                 else
1172                         p = e_dialinginfo.id;
1173                 do {
1174                         number[0] = '\0';
1175                         while(*p!=',' && *p!='\0')
1176                                 SCCAT(number, *p++);
1177                         if (*p == ',')
1178                                 p++;
1179                         /* found number */
1180                         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");
1181                         /* hunt for mISDNport and create Port */
1182                         /* hunt for mISDNport and create Port */
1183                         mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1184                         if (!mISDNport) {
1185                                 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1186                                 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1187                                 end_trace();
1188                                 goto check_anycall_extern;
1189                         }
1190                         /* creating EXTERNAL port*/
1191                         SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1192 #ifdef WITH_SS5
1193                         if (mISDNport->ss5)
1194                                 port = ss5_hunt_line(mISDNport);
1195                         else
1196 #endif
1197                         if (!mISDNport->gsm)
1198                                 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);
1199                         else
1200 #ifdef WITH_GSM
1201                                 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1202 #else
1203                                 port = NULL;
1204 #endif
1205                         if (!port)
1206                                 FATAL("No memory for Port instance\n");
1207                         earlyb = mISDNport->earlyb;
1208                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1209                         memset(&dialinginfo, 0, sizeof(dialinginfo));
1210                         if (e_dialinginfo.keypad[0])
1211                                 SCPY(dialinginfo.keypad, number);
1212                         else
1213                                 SCPY(dialinginfo.id, number);
1214                         dialinginfo.itype = INFO_ITYPE_ISDN;
1215                         dialinginfo.ntype = e_dialinginfo.ntype;
1216                         portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1217                         if (!portlist) {
1218                                 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1219                                 delete port;
1220                                 goto check_anycall_extern;
1221                         }
1222 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1223                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1224                         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1225                         memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1226                         memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1227                         memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1228 //terminal                      SCPY(message->param.setup.from_terminal, e_ext.number);
1229 //terminal                      if (e_dialinginfo.id)
1230 //terminal                              SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1231                                 /* handle restricted caller ids */
1232                         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);
1233                         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);
1234                         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);
1235                         /* display callerid if desired for extension */
1236                         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));
1237                         message_put(message);
1238                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1239                         anycall = 1;
1240                 } while(*p);
1241
1242                 check_anycall_extern:
1243                 /* now we have all ports created */
1244                 if (!anycall) {
1245                         trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1246                         end_trace();
1247                         if (!ea_endpoint->ep_join_id)
1248                                 break;
1249                         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1250                         return; /* must exit here */
1251                 }
1252                 break;
1253         }
1254
1255 }
1256
1257 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1258 {
1259         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1260
1261         if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1262                 return 0;
1263
1264         unsched_timer(&ea->e_redial_timeout);
1265         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1266         ea->e_multipoint_cause = 0;
1267         ea->e_multipoint_location = 0;
1268         ea->new_state(EPOINT_STATE_IN_OVERLAP);
1269         ea->e_join_pattern = 0;
1270         ea->process_dialing(1);
1271         /* we must exit, because our endpoint might be gone */
1272
1273         return 0;
1274 }
1275
1276 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1277 {
1278         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1279
1280         if (!ea->e_action) {
1281                 unsched_timer(&ea->e_redial_timeout);
1282                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1283                 ea->process_dialing(0);
1284                 /* we must exit, because our endpoint might be gone */
1285         }
1286
1287         return 0;
1288 }
1289
1290 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1291 {
1292         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1293
1294         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1295
1296         ea->new_state(EPOINT_STATE_OUT_SETUP);
1297         /* call special setup routine */
1298         ea->out_setup();
1299
1300         return 0;
1301 }
1302
1303 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1304 {
1305         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1306
1307         /* leave power dialing on */
1308         ea->e_powerdial_on = 1;
1309         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1310
1311         /* redial */
1312         ea->e_ruleset = ruleset_main;
1313         if (ea->e_ruleset)
1314                 ea->e_rule = ea->e_ruleset->rule_first;
1315         ea->e_action = NULL;
1316         ea->new_state(EPOINT_STATE_IN_OVERLAP);
1317         ea->process_dialing(0);
1318
1319         return 0;
1320 }
1321
1322 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1323 {
1324         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1325         struct port_list *portlist;
1326         struct lcr_msg *message;
1327
1328         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1329
1330         /* release all ports */
1331         while((portlist = ea->ea_endpoint->ep_portlist)) {
1332                 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1333                 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1334                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1335                 message_put(message);
1336                 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1337                 ea->ea_endpoint->free_portlist(portlist);
1338         }
1339         /* put on hold */
1340         message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1341         message->param.audiopath = 0;
1342         message_put(message);
1343         /* indicate no patterns */
1344         message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1345         message_put(message);
1346         /* set setup state, since we have no response from the new join */
1347         ea->new_state(EPOINT_STATE_OUT_SETUP);
1348
1349         return 0;
1350 }
1351
1352 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1353 {
1354         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1355
1356         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);
1357         ea->out_setup();
1358
1359         return 0;
1360 }
1361
1362 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1363 {
1364         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1365
1366         if (ea->e_state == EPOINT_STATE_IDLE) {
1367                 /* epoint is idle, check callback */
1368                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1369                 ea->new_state(EPOINT_STATE_OUT_SETUP);
1370                 ea->out_setup();
1371         }
1372
1373         return 0;
1374 }
1375
1376 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1377 {
1378         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1379
1380         if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1381                 struct port_list *portlist;
1382
1383                 ea->e_ruleset = ruleset_main;
1384                 if (ea->e_ruleset)
1385                         ea->e_rule = ea->e_ruleset->rule_first;
1386                 ea->e_action = NULL;
1387                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1388                 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1389                 end_trace();
1390                 ea->e_connectedmode = 0;
1391                 ea->e_dtmf = 0;
1392                 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1393                 portlist = ea->ea_endpoint->ep_portlist;
1394                 if (portlist) {
1395                         ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1396                         ea->set_tone(portlist, "cause_10");
1397                 }
1398         }
1399
1400         return 0;
1401 }
1402
1403 /* doing a hookflash */
1404 void EndpointAppPBX::hookflash(void)
1405 {
1406         class Port *port;
1407         time_t now;
1408
1409         /* be sure that we are active */
1410         notify_active();
1411         e_tx_state = NOTIFY_STATE_ACTIVE;
1412
1413         trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1414         end_trace();
1415         if (ea_endpoint->ep_use > 1) {
1416                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1417                 return;
1418         }
1419         /* dialtone after pressing the hash key */
1420         process_hangup(e_join_cause, e_join_location);
1421         e_multipoint_cause = 0;
1422         e_multipoint_location = 0;
1423         port = find_port_id(ea_endpoint->ep_portlist->port_id);
1424         if (port) {
1425                 port->set_echotest(0);
1426         }
1427         if (ea_endpoint->ep_join_id) {
1428                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1429         }
1430         e_ruleset = ruleset_main;
1431         if (e_ruleset)
1432                 e_rule = e_ruleset->rule_first;
1433         e_action = NULL;
1434         new_state(EPOINT_STATE_IN_OVERLAP);
1435         e_connectedmode = 1;
1436         SCPY(e_dialinginfo.id, e_ext.prefix);
1437         e_extdialing = e_dialinginfo.id;
1438         e_join_pattern = 0;
1439         if (e_dialinginfo.id[0]) {
1440                 set_tone(ea_endpoint->ep_portlist, "dialing");
1441                 process_dialing(0);
1442         } else {
1443                 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1444         }
1445         time(&now);
1446         e_dtmf_time = now;
1447         e_dtmf_last = '\0';
1448 }
1449
1450
1451 /* messages from port
1452  */
1453 /* port MESSAGE_SETUP */
1454 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1455 {
1456         struct lcr_msg          *message;
1457         char                    buffer[256];
1458         int                     writeext;               /* flags need to write extension after modification */
1459         class Port              *port;
1460         struct interface        *interface;
1461
1462         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1463         
1464         portlist->port_type = param->setup.port_type;
1465         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
1466         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
1467         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
1468         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
1469
1470         /* convert (inter-)national number type */
1471         SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1472         e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1473
1474 //      e_dtmf = param->setup.dtmf;
1475         /* screen incoming caller id */
1476         interface = interface_first;
1477         while(interface) {
1478                 if (!strcmp(e_callerinfo.interface, interface->name)) {
1479                         break;
1480                 }
1481                 interface = interface->next;
1482         }
1483         if (interface) {
1484                 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1485                 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1486         }
1487
1488         /* process extension */
1489         if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1490                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1491                 /* port makes call from extension */
1492                 SCPY(e_callerinfo.extension, e_callerinfo.id);
1493                 SCPY(e_ext.number, e_callerinfo.extension);
1494                 SCPY(e_extension_interface, e_callerinfo.interface);
1495         } else {
1496                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1497         }
1498
1499         if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1500                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1501
1502                 /* get extension's info about caller */
1503                 if (!read_extension(&e_ext, e_ext.number)) {
1504                         /* extension doesn't exist */
1505                         trace_header("EXTENSION (not created)", DIRECTION_IN);
1506                         add_trace("extension", NULL, "%s", e_ext.number);
1507                         end_trace();
1508                         message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1509                         new_state(EPOINT_STATE_OUT_DISCONNECT);
1510                         set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1511                         e_ext.number[0] = '\0'; /* no terminal */
1512                         return;
1513                 }
1514                 writeext = 0;
1515
1516                 /* put prefix (next) in front of e_dialinginfo.id */
1517                 if (e_ext.next[0]) {
1518                         SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1519                         SCPY(e_dialinginfo.id, buffer);
1520                         e_ext.next[0] = '\0';
1521                         writeext = 1;
1522                 } else if (e_ext.prefix[0]) {
1523                         SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1524                         SCPY(e_dialinginfo.id, buffer);
1525                 }
1526
1527                 /* screen caller id by extension's config */
1528                 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1529                 if (e_ext.name[0])
1530                         SCPY(e_callerinfo.name, e_ext.name);
1531                 /* use caller id (or if exist: id_next_call) for this call */
1532                 if (e_ext.id_next_call_present >= 0) {
1533                         SCPY(e_callerinfo.id, e_ext.id_next_call);
1534                         /* if we restrict the pesentation */
1535                         if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1536                                 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1537                         else    e_callerinfo.present = e_ext.id_next_call_present;
1538                         e_callerinfo.ntype = e_ext.id_next_call_type;
1539                         e_ext.id_next_call_present = -1;
1540                         writeext = 1;
1541                 } else {
1542                         SCPY(e_callerinfo.id, e_ext.callerid);
1543                         /* if we restrict the pesentation */
1544                         if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1545                                 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1546                         else    e_callerinfo.present = e_ext.callerid_present;
1547                         e_callerinfo.ntype = e_ext.callerid_type;
1548                 }
1549                 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1550
1551                 /* extension is written */
1552                 if (writeext)
1553                         write_extension(&e_ext, e_ext.number);
1554
1555                 /* set volume of rx and tx */
1556                 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1557                 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1558                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1559                         message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1560                         message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1561                         message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1562                         message_put(message);
1563                 }
1564
1565                 /* start recording if enabled */
1566                 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1567                         /* check if we are a terminal */
1568                         if (e_ext.number[0] == '\0')
1569                                 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1570                         else {
1571                                 port = find_port_id(portlist->port_id);
1572                                 if (port)
1573                                         port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1574                         }
1575                 }
1576         } else {
1577                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1578                 /* no terminal identification */
1579                 e_ext.number[0] = '\0';
1580                 e_extension_interface[0] = '\0';
1581                 memset(&e_ext, 0, sizeof(e_ext));
1582                 e_ext.rights = 4; /* right to dial internat */
1583         }
1584
1585         /* incoming call */
1586         e_ruleset = ruleset_main;
1587         if (e_ruleset)
1588                 e_rule = e_ruleset->rule_first;
1589         e_action = NULL;
1590         e_extdialing = e_dialinginfo.id;
1591         new_state(EPOINT_STATE_IN_SETUP);
1592         if (e_dialinginfo.id[0]) {
1593                 set_tone(portlist, "dialing");
1594         } else {
1595                 if (e_ext.number[0])
1596                         set_tone(portlist, "dialpbx");
1597                 else
1598                         set_tone(portlist, "dialtone");
1599         }
1600         process_dialing(0);
1601         if (e_state == EPOINT_STATE_IN_SETUP) {
1602                 /* request MORE info, if not already at higher state */
1603                 new_state(EPOINT_STATE_IN_OVERLAP);
1604                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1605                 message_put(message);
1606                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1607         }
1608 }
1609
1610 /* port MESSAGE_INFORMATION */
1611 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1612 {
1613         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1614
1615         /* ignore information message without digit information */
1616         if (!param->information.id[0])
1617                 return;
1618
1619         e_overlap = 1;
1620
1621         /* turn off dtmf detection, in case dtmf is sent with keypad information */
1622         if (e_dtmf) {
1623                 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1624                 end_trace();
1625                 e_dtmf = 0;
1626         }
1627
1628         /* if vbox_play is done, the information are just used as they come */
1629         if (e_action)
1630         if (e_action->index == ACTION_VBOX_PLAY) {
1631                 /* concat dialing string */
1632                 SCAT(e_dialinginfo.id, param->information.id);
1633                 process_dialing(0);
1634                 return;
1635         }
1636
1637         /* keypad when disconnect but in connected mode */
1638         if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1639                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1640                 /* processing keypad function */
1641                 if (param->information.id[0] == '0') {
1642                         hookflash();
1643                 }
1644                 return;
1645         }
1646
1647         /* keypad when connected */
1648         if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1649                 if (e_ext.keypad || e_enablekeypad) {
1650                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1651                         /* processing keypad function */
1652                         if (param->information.id[0] == '0') {
1653                                 hookflash();
1654                         }
1655                         if (param->information.id[0])
1656                                 keypad_function(param->information.id[0]);
1657                 } else {
1658                         if (e_ext.number[0])
1659                                 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1660                         else
1661                                 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1662                         end_trace();
1663                 }
1664                 return;
1665         }
1666         if (e_state != EPOINT_STATE_IN_OVERLAP) {
1667                 if (e_ext.number[0])
1668                         trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1669                 else
1670                         trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1671                 end_trace();
1672                 return;
1673         }
1674         if (!param->information.id[0])
1675                 return;
1676         if (e_dialinginfo.id[0]=='\0' && !e_action) {
1677                 set_tone(portlist, "dialing");
1678         }
1679         if (e_action)
1680         if (e_action->index==ACTION_OUTDIAL
1681          || e_action->index==ACTION_EXTERNAL
1682          || e_action->index==ACTION_REMOTE) {
1683                 if (!e_extdialing)
1684                         set_tone(portlist, "dialing");
1685                 else if (!e_extdialing[0])
1686                         set_tone(portlist, "dialing");
1687         }
1688         /* concat dialing string */
1689         SCAT(e_dialinginfo.id, param->information.id);
1690         process_dialing(0);
1691 }
1692
1693 /* port MESSAGE_DTMF */
1694 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1695 {
1696         time_t now;
1697
1698         time(&now);
1699
1700         /* only if dtmf detection is enabled */
1701         if (!e_dtmf) {
1702                 trace_header("DTMF (disabled)", DIRECTION_IN);
1703                 end_trace();
1704                 return;
1705         }
1706         trace_header("DTMF", DIRECTION_IN);
1707         add_trace("digit", NULL, "%c", param->dtmf);
1708         end_trace();
1709
1710 #if 0
1711 NOTE: vbox is now handled due to overlap state
1712         /* if vbox_play is done, the dtmf digits are just used as they come */
1713         if (e_action)
1714         if (e_action->index == ACTION_VBOX_PLAY) {
1715                 /* concat dialing string */
1716                 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1717                         e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1718                         e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1719                         process_dialing(0);
1720                 }
1721                 /* continue to process *X# sequences */
1722         }
1723 #endif
1724
1725         /* check for *X# sequence */
1726         if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1727                 if (e_dtmf_time+3 < now) {
1728                         /* the last digit was too far in the past to be a sequence */
1729                         if (param->dtmf == '*')
1730                                 /* only start is allowed in the sequence */
1731                                 e_dtmf_last = '*';
1732                         else
1733                                 e_dtmf_last = '\0';
1734                 } else {
1735                         /* we have a sequence of digits, see what we got */
1736                         if (param->dtmf == '*')
1737                                 e_dtmf_last = '*';
1738                         else if (param->dtmf>='0' && param->dtmf<='9') {
1739                                 /* we need to have a star before we receive the digit of the sequence */
1740                                 if (e_dtmf_last == '*')
1741                                         e_dtmf_last = param->dtmf;
1742                         } else if (param->dtmf == '#') {
1743                                 /* the hash key */
1744                                 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1745                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1746                                         if (e_dtmf_last == '0') {
1747                                                 hookflash();
1748                                                 return;
1749                                         }
1750                                         /* processing keypad function */
1751                                         if (param->dtmf)
1752                                                 keypad_function(e_dtmf_last);
1753                                         e_dtmf_last = '\0';
1754                                 }
1755                         }
1756                 }
1757
1758                 /* set last time of dtmf */
1759                 e_dtmf_time = now;
1760                 return;
1761         }
1762
1763         /* check for ## hookflash during dialing */
1764         if (e_action)
1765         if (e_action->index==ACTION_PASSWORD
1766          || e_action->index==ACTION_PASSWORD_WRITE)
1767                 goto password;
1768         if (param->dtmf=='#') { /* current digit is '#' */
1769                 if (e_state==EPOINT_STATE_IN_DISCONNECT
1770                  || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1771                         hookflash();
1772                         return;
1773                 } else {
1774                         e_dtmf_time = now;
1775                         e_dtmf_last = '#';
1776                 }
1777         } else {
1778                 password:
1779                 e_dtmf_time = now;
1780                 e_dtmf_last = '\0';
1781         }
1782         
1783
1784         /* dialing using dtmf digit */
1785         if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1786                 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1787                         set_tone(portlist, "dialing");
1788                 }
1789                 /* concat dialing string */
1790                 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1791                         e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1792                         e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1793                         process_dialing(0);
1794                 }
1795         }
1796 }
1797
1798 /* port MESSAGE_CRYPT */
1799 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1800 {
1801         /* send crypt response to cryptman */
1802         if (param->crypt.type == CR_MESSAGE_IND)
1803                 cryptman_msg2man(param->crypt.data, param->crypt.len);
1804         else
1805                 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1806 }
1807
1808 /* port MESSAGE_OVERLAP */
1809 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1810 {
1811         struct lcr_msg *message;
1812
1813         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1814
1815         /* signal to call tool */
1816         admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1817
1818         if (e_dialing_queue[0] && portlist) {
1819                 /* send what we have not dialed yet, because we had no setup complete */
1820                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1821                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1822                 SCPY(message->param.information.id, e_dialing_queue);
1823                 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1824                 message_put(message);
1825                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1826                 e_dialing_queue[0] = '\0';
1827         }
1828         /* check if pattern is available */
1829         if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1830                 /* indicate patterns */
1831                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1832                 message_put(message);
1833
1834                 /* connect audio, if not already */
1835                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1836                 message->param.audiopath = 1;
1837                 message_put(message);
1838         } else {
1839                 /* indicate no patterns */
1840                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1841                 message_put(message);
1842
1843                 /* disconnect audio, if not already */
1844                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1845                 message->param.audiopath = 0;
1846                 message_put(message);
1847         }
1848         new_state(EPOINT_STATE_OUT_OVERLAP);
1849         /* if we are in a join */
1850         if (ea_endpoint->ep_join_id) { 
1851                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1852                 memcpy(&message->param, param, sizeof(union parameter));
1853                 message_put(message);
1854         }
1855 }
1856
1857 /* port MESSAGE_PROCEEDING */
1858 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1859 {
1860         struct lcr_msg *message;
1861
1862         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1863
1864         /* signal to call tool */
1865         admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1866
1867         e_state = EPOINT_STATE_OUT_PROCEEDING;
1868         /* check if pattern is availatle */
1869         if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1870                 /* indicate patterns */
1871                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1872                 message_put(message);
1873
1874                 /* connect audio, if not already */
1875                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1876                 message->param.audiopath = 1;
1877                 message_put(message);
1878         } else {
1879                 /* indicate no patterns */
1880                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1881                 message_put(message);
1882
1883                 /* disconnect audio, if not already */
1884                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1885                 message->param.audiopath = 0;
1886                 message_put(message);
1887         }
1888         /* if we are in a call */
1889         if (ea_endpoint->ep_join_id) { 
1890                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1891                 memcpy(&message->param, param, sizeof(union parameter));
1892                 message_put(message);
1893         }
1894 }
1895
1896 /* port MESSAGE_ALERTING */
1897 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1898 {
1899         struct lcr_msg *message;
1900
1901         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1902
1903         /* signal to call tool */
1904         admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1905 //#warning hack!!
1906 //      if (e_adminid)
1907 //              set_tone(portlist, "hold");
1908
1909         new_state(EPOINT_STATE_OUT_ALERTING);
1910         /* check if pattern is available */
1911         if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1912                 /* indicate patterns */
1913                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1914                 message_put(message);
1915
1916                 /* connect audio, if not already */
1917                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1918                 message->param.audiopath = 1;
1919                 message_put(message);
1920         } else {
1921                 /* indicate no patterns */
1922                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1923                 message_put(message);
1924
1925                 /* disconnect audio, if not already */
1926                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1927                 message->param.audiopath = 0;
1928                 message_put(message);
1929         }
1930         /* if we are in a call */
1931         if (ea_endpoint->ep_join_id) { 
1932                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1933                 memcpy(&message->param, param, sizeof(union parameter));
1934                 message_put(message);
1935         }
1936 }
1937
1938 /* port MESSAGE_CONNECT */
1939 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1940 {
1941         struct lcr_msg *message;
1942         char buffer[256];
1943         unsigned int port_id = portlist->port_id;
1944         struct port_list *tportlist;
1945         class Port *port;
1946         struct interface        *interface;
1947         time_t now;
1948
1949         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1950
1951         /* signal to call tool */
1952         admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1953
1954         memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_connectinfo));
1955         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1956         while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1957                 tportlist = ea_endpoint->ep_portlist;
1958                 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1959                         tportlist = tportlist->next;
1960                 if (tportlist->port_id == port_id)
1961                         FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1962                 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1963                 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1964                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1965                 message_put(message);
1966                 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1967                 ea_endpoint->free_portlist(tportlist);
1968         }
1969         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1970
1971         time(&now);
1972         e_start = now;
1973
1974         /* screen incoming connected id */
1975         interface = interface_first;
1976         while(interface) {
1977                 if (!strcmp(e_connectinfo.interface, interface->name)) {
1978                         break;
1979                 }
1980                 interface = interface->next;
1981         }
1982         if (interface)
1983                 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1984
1985         /* screen connected name */
1986         if (e_ext.name[0])
1987                 SCPY(e_connectinfo.name, e_ext.name);
1988
1989         /* add internal id to colp */
1990         SCPY(e_connectinfo.extension, e_ext.number);
1991
1992         /* we store the connected port number */
1993         SCPY(e_extension_interface, e_connectinfo.interface);
1994
1995         /* for internal and am calls, we get the extension's id */
1996         if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1997                 SCPY(e_connectinfo.id, e_ext.callerid);
1998                 SCPY(e_connectinfo.extension, e_ext.number);
1999                 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2000                 e_connectinfo.ntype = e_ext.callerid_type;
2001                 e_connectinfo.present = e_ext.callerid_present;
2002         }
2003         if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2004                 e_connectinfo.itype = INFO_ITYPE_VBOX;
2005                 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2006         }
2007
2008         new_state(EPOINT_STATE_CONNECT);
2009
2010         /* set volume of rx and tx */
2011         if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2012                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2013                 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2014                 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2015                 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2016                 message_put(message);
2017         }
2018
2019         unsched_timer(&e_cfnr_timeout);
2020         unsched_timer(&e_cfnr_call_timeout);
2021         if (e_ext.number[0])
2022                 e_dtmf = 1; /* allow dtmf */
2023
2024         /* modify colp */
2025         /* other calls with no caller id (or not available for the extension) and force colp */
2026         if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2027                 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2028                 if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT || portlist->port_type==PORT_TYPE_GSM_OUT) { /* external extension answered */
2029                         port = find_port_id(portlist->port_id);
2030                         if (port) {
2031                                 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2032                                 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2033                         }
2034                 }
2035         }
2036
2037         /* send connect to join */
2038         if (ea_endpoint->ep_join_id) {
2039                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2040                 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2041                 message_put(message);
2042
2043                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2044                 message->param.audiopath = 1;
2045                 message_put(message);
2046         } else if (!e_adminid) {
2047                 /* callback */
2048                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2049                 SCPY(e_ext.number, e_cbcaller);
2050                 new_state(EPOINT_STATE_IN_OVERLAP);
2051                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2052
2053                 /* get extension's info about terminal */
2054                 if (!read_extension(&e_ext, e_ext.number)) {
2055                         /* extension doesn't exist */
2056                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2057                         message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2058                         new_state(EPOINT_STATE_OUT_DISCONNECT);
2059                         set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2060                         return;
2061                 }
2062
2063                 /* put prefix in front of e_cbdialing */
2064                 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2065                 SCPY(e_dialinginfo.id, buffer);
2066                 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2067                 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2068
2069                 /* use caller id (or if exist: id_next_call) for this call */
2070                 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2071                 SCPY(e_callerinfo.extension, e_ext.number);
2072                 if (e_ext.id_next_call_present >= 0) {
2073                         SCPY(e_callerinfo.id, e_ext.id_next_call);
2074                         e_callerinfo.present = e_ext.id_next_call_present;
2075                         e_callerinfo.ntype = e_ext.id_next_call_type;
2076                         e_ext.id_next_call_present = -1;
2077                         /* extension is written */
2078                         write_extension(&e_ext, e_ext.number);
2079                 } else {
2080                         SCPY(e_callerinfo.id, e_ext.callerid);
2081                         e_callerinfo.present = e_ext.callerid_present;
2082                         e_callerinfo.ntype = e_ext.callerid_type;
2083                 }
2084                 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2085
2086                 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2087                 e_dtmf = 1;
2088
2089                 /* check if caller id is NOT authenticated */
2090                 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2091                         /* make call state to enter password */
2092                         new_state(EPOINT_STATE_IN_OVERLAP);
2093                         e_action = &action_password_write;
2094                         unsched_timer(&e_match_timeout);
2095                         e_match_to_action = NULL;
2096                         e_dialinginfo.id[0] = '\0';
2097                         e_extdialing = strchr(e_dialinginfo.id, '\0');
2098                         schedule_timer(&e_password_timeout, 20, 0);
2099                         process_dialing(0);
2100                 } else {
2101                         /* incoming call (callback) */
2102                         e_ruleset = ruleset_main;
2103                         if (e_ruleset)
2104                                 e_rule = e_ruleset->rule_first;
2105                         e_action = NULL;
2106                         e_extdialing = e_dialinginfo.id;
2107                         if (e_dialinginfo.id[0]) {
2108                                 set_tone(portlist, "dialing");
2109                                 process_dialing(0);
2110                         } else {
2111                                 set_tone(portlist, "dialpbx");
2112                         }
2113                 }
2114         } else { /* testcall */
2115                 set_tone(portlist, "hold");
2116         }
2117
2118         /* start recording if enabled, not when answering machine answers */
2119         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)) {
2120                 /* check if we are a terminal */
2121                 if (e_ext.number[0] == '\0')
2122                         PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2123                 else {
2124                         port = find_port_id(portlist->port_id);
2125                         if (port)
2126                                 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2127                 }
2128         }
2129 }
2130
2131 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2132 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2133 {
2134         struct lcr_msg  *message;
2135         char            buffer[256];
2136         unsigned int    port_id = portlist->port_id;
2137         int             cause,
2138                         location;
2139
2140         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2141
2142         /* signal to call tool */
2143         admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2144
2145 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2146         if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2147                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2148                 return;
2149         }
2150
2151         /* collect cause */
2152         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);
2153         collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2154         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2155
2156         /* check if we have more than one portlist relation and we just ignore the disconnect */
2157         if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2158                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2159                 portlist = ea_endpoint->ep_portlist;
2160                 while(portlist) {
2161                         if (portlist->port_id == port_id)
2162                                 break;
2163                         portlist = portlist->next;
2164                 }
2165                 if (!portlist)
2166                         FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2167                 if (message_type != MESSAGE_RELEASE) {
2168                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2169                         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2170                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2171                         message_put(message);
2172                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2173                 }
2174                 ea_endpoint->free_portlist(portlist);
2175                 return; /* one relation removed */ 
2176         }
2177         if (e_state == EPOINT_STATE_CONNECT) {
2178                 /* use cause from port after connect */
2179                 cause = param->disconnectinfo.cause;
2180                 location = param->disconnectinfo.location;
2181         } else {
2182                 /* use multipoint cause if no connect yet */
2183                 if (e_multipoint_cause) {
2184                         cause = e_multipoint_cause;
2185                         location = e_multipoint_location;
2186                 } else {
2187                         cause = CAUSE_NOUSER;
2188                         location = LOCATION_PRIVATE_LOCAL;
2189                 }
2190         }
2191
2192         unsched_timer(&e_cfnr_timeout);
2193         unsched_timer(&e_cfnr_call_timeout);
2194
2195         /* process hangup */
2196         process_hangup(e_join_cause, e_join_location);
2197         e_multipoint_cause = 0;
2198         e_multipoint_location = 0;
2199
2200         if (message_type == MESSAGE_DISCONNECT) {
2201                 /* tone to disconnected end */
2202                 SPRINT(buffer, "cause_%02x", cause);
2203                 if (ea_endpoint->ep_portlist)
2204                         set_tone(ea_endpoint->ep_portlist, buffer);
2205
2206                 new_state(EPOINT_STATE_IN_DISCONNECT);
2207         }
2208
2209         if (ea_endpoint->ep_join_id) {
2210                 int haspatterns = 0;
2211                 /* check if pattern is available */
2212                 if (ea_endpoint->ep_portlist)
2213                 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2214                 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 
2215                  && message_type != MESSAGE_RELEASE) // if we release, we are done
2216                         haspatterns = 1;
2217                 if (haspatterns) {
2218                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2219                         /* indicate patterns */
2220                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2221                         message_put(message);
2222                         /* connect audio, if not already */
2223                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2224                         message->param.audiopath = 1;
2225                         message_put(message);
2226                         /* send disconnect */
2227                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2228                         memcpy(&message->param, param, sizeof(union parameter));
2229                         message_put(message);
2230                         /* disable encryption if disconnected */
2231 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2232                         if (e_crypt_state)
2233                                 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2234                         return;
2235                 } else {
2236                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2237                 }
2238         }
2239         if (message_type == MESSAGE_RELEASE)
2240                 ea_endpoint->free_portlist(portlist);
2241         release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2242         return; /* must exit here */
2243 }
2244
2245 /* port MESSAGE_TIMEOUT */
2246 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2247 {
2248         char cause[16];
2249
2250         trace_header("TIMEOUT", DIRECTION_IN);
2251         message_type = MESSAGE_DISCONNECT;
2252         switch (param->state) {
2253                 case PORT_STATE_OUT_SETUP:
2254                 case PORT_STATE_OUT_OVERLAP:
2255                 add_trace("state", NULL, "outgoing setup/dialing");
2256                 end_trace();
2257                 /* no user responding */
2258                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2259                 return; /* must exit here */
2260
2261                 case PORT_STATE_IN_SETUP:
2262                 case PORT_STATE_IN_OVERLAP:
2263                 add_trace("state", NULL, "incoming setup/dialing");
2264                 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2265                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2266                 break;
2267
2268                 case PORT_STATE_OUT_PROCEEDING:
2269                 add_trace("state", NULL, "outgoing proceeding");
2270                 end_trace();
2271                 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2272                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2273                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2274                 return; /* must exit here */
2275
2276                 case PORT_STATE_IN_PROCEEDING:
2277                 add_trace("state", NULL, "incoming proceeding");
2278                 param->disconnectinfo.cause = CAUSE_NOUSER;
2279                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2280                 break;
2281
2282                 case PORT_STATE_OUT_ALERTING:
2283                 add_trace("state", NULL, "outgoing alerting");
2284                 end_trace();
2285                 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2286                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2287                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2288                 return; /* must exit here */
2289
2290                 case PORT_STATE_CONNECT:
2291                 add_trace("state", NULL, "connect");
2292                 end_trace();
2293                 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2294                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2295                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2296                 return; /* must exit here */
2297
2298                 case PORT_STATE_IN_ALERTING:
2299                 add_trace("state", NULL, "incoming alerting");
2300                 param->disconnectinfo.cause = CAUSE_NOANSWER;
2301                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2302                 break;
2303
2304                 case PORT_STATE_IN_DISCONNECT:
2305                 case PORT_STATE_OUT_DISCONNECT:
2306                 add_trace("state", NULL, "disconnect");
2307                 end_trace();
2308                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2309                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2310                 return; /* must exit here */
2311
2312                 default:
2313                 param->disconnectinfo.cause = 31; /* normal unspecified */
2314                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2315         }
2316         end_trace();
2317         /* release call, disconnect isdn */
2318         e_join_pattern = 0;
2319         new_state(EPOINT_STATE_OUT_DISCONNECT);
2320         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2321         SCPY(e_tone, cause);
2322         while(portlist) {
2323                 set_tone(portlist, cause);
2324                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2325                 portlist = portlist->next;
2326         }
2327         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2328 }
2329
2330 /* port MESSAGE_NOTIFY */
2331 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2332 {
2333         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2334
2335         struct lcr_msg *message;
2336         const char *logtext = "";
2337         char buffer[64];
2338
2339         /* signal to call tool */
2340         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);
2341         if (param->notifyinfo.notify) {
2342                 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2343         }
2344
2345         /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2346         if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2347                 case INFO_NOTIFY_REMOTE_HOLD:
2348                 case INFO_NOTIFY_USER_SUSPENDED:
2349                 /* tell call about it */
2350                 if (ea_endpoint->ep_join_id) {
2351                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2352                         message->param.audiopath = 0;
2353                         message_put(message);
2354                 }
2355                 break;
2356
2357                 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2358                 case INFO_NOTIFY_USER_RESUMED:
2359                 /* set volume of rx and tx */
2360                 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2361                 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2362                 if (portlist) {
2363                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2364                         message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2365                         message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2366                         message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2367                         message_put(message);
2368                 }
2369                 /* set current tone */
2370                 if (portlist)
2371                         set_tone(portlist, e_tone);
2372                 /* tell call about it */
2373                 if (ea_endpoint->ep_join_id) {
2374                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2375                         message->param.audiopath = 1;
2376                         message_put(message);
2377                 }
2378                 break;
2379         }
2380
2381         /* get name of notify */
2382         switch(param->notifyinfo.notify) {
2383                 case 0x00:
2384                 logtext = "NULL";
2385                 break;
2386                 case 0x80:
2387                 logtext = "USER_SUSPENDED";
2388                 break;
2389                 case 0x82:
2390                 logtext = "BEARER_SERVICE_CHANGED";
2391                 break;
2392                 case 0x81:
2393                 logtext = "USER_RESUMED";
2394                 break;
2395                 case 0xc2:
2396                 logtext = "CONFERENCE_ESTABLISHED";
2397                 break;
2398                 case 0xc3:
2399                 logtext = "CONFERENCE_DISCONNECTED";
2400                 break;
2401                 case 0xc4:
2402                 logtext = "OTHER_PARTY_ADDED";
2403                 break;
2404                 case 0xc5:
2405                 logtext = "ISOLATED";
2406                 break;
2407                 case 0xc6:
2408                 logtext = "REATTACHED";
2409                 break;
2410                 case 0xc7:
2411                 logtext = "OTHER_PARTY_ISOLATED";
2412                 break;
2413                 case 0xc8:
2414                 logtext = "OTHER_PARTY_REATTACHED";
2415                 break;
2416                 case 0xc9:
2417                 logtext = "OTHER_PARTY_SPLIT";
2418                 break;
2419                 case 0xca:
2420                 logtext = "OTHER_PARTY_DISCONNECTED";
2421                 break;
2422                 case 0xcb:
2423                 logtext = "CONFERENCE_FLOATING";
2424                 break;
2425                 case 0xcc:
2426                 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2427                 break;
2428                 case 0xcf:
2429                 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2430                 break;
2431                 case 0xe0:
2432                 logtext = "CALL_IS_A_WAITING_CALL";
2433                 break;
2434                 case 0xe8:
2435                 logtext = "DIVERSION_ACTIVATED";
2436                 break;
2437                 case 0xe9:
2438                 logtext = "RESERVED_CT_1";
2439                 break;
2440                 case 0xea:
2441                 logtext = "RESERVED_CT_2";
2442                 break;
2443                 case 0xee:
2444                 logtext = "REVERSE_CHARGING";
2445                 break;
2446                 case 0xf9:
2447                 logtext = "REMOTE_HOLD";
2448                 break;
2449                 case 0xfa:
2450                 logtext = "REMOTE_RETRIEVAL";
2451                 break;
2452                 case 0xfb:
2453                 logtext = "CALL_IS_DIVERTING";
2454                 break;
2455                 default:
2456                 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2457                 logtext = buffer;
2458
2459         }
2460
2461         /* notify call if available */
2462         if (ea_endpoint->ep_join_id) {
2463                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2464                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
2465                 message_put(message);
2466         }
2467
2468 }
2469
2470 /* port MESSAGE_FACILITY */
2471 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2472 {
2473         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2474
2475         struct lcr_msg *message;
2476
2477         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2478         memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2479         message_put(message);
2480 }
2481
2482 /* port MESSAGE_SUSPEND */
2483 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2484 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2485 {
2486         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2487
2488         /* epoint is now parked */
2489         ea_endpoint->ep_park = 1;
2490         memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2491         ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2492
2493         /* remove port relation */
2494         ea_endpoint->free_portlist(portlist);
2495 }
2496
2497 /* port MESSAGE_RESUME */
2498 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2499 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2500 {
2501         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2502
2503         /* epoint is now resumed */
2504         ea_endpoint->ep_park = 0;
2505
2506 }
2507
2508
2509 /* port sends message to the endpoint
2510  */
2511 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2512 {
2513         struct port_list *portlist;
2514
2515         portlist = ea_endpoint->ep_portlist;
2516         while(portlist) {
2517                 if (port_id == portlist->port_id)
2518                         break;
2519                 portlist = portlist->next;
2520         }
2521         if (!portlist) {
2522                 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);
2523                 return;
2524         }
2525
2526 //      PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2527         switch(message_type) {
2528                 case MESSAGE_DATA: /* data from port */
2529                 /* check if there is a call */
2530                 if (!ea_endpoint->ep_join_id)
2531                         break;
2532                 /* continue if only one portlist */
2533                 if (ea_endpoint->ep_portlist->next != NULL)
2534                         break;
2535                 /* forward message */
2536                 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);  
2537                 break;
2538
2539                 case MESSAGE_TONE_EOF: /* tone is end of file */
2540                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2541                 if (e_action) {
2542                         if (e_action->index == ACTION_VBOX_PLAY) {
2543                                 vbox_message_eof();
2544                         }
2545                         if (e_action->index == ACTION_EFI) {
2546                                 efi_message_eof();
2547                         }
2548                 }
2549                 break;
2550
2551                 case MESSAGE_TONE_COUNTER: /* counter info received */
2552                 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);
2553                 if (e_action)
2554                 if (e_action->index == ACTION_VBOX_PLAY) {
2555                         e_vbox_counter = param->counter.current;
2556                         if (param->counter.max >= 0)
2557                                 e_vbox_counter_max = param->counter.max;
2558                 }
2559                 break;
2560
2561                 /* PORT sends SETUP message */
2562                 case MESSAGE_SETUP:
2563                 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);
2564                 if (e_state!=EPOINT_STATE_IDLE) {
2565                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2566                         break;
2567                 }
2568                 port_setup(portlist, message_type, param);
2569                 break;
2570
2571                 /* PORT sends INFORMATION message */
2572                 case MESSAGE_INFORMATION: /* additional digits received */
2573                 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);
2574                 port_information(portlist, message_type, param);
2575                 break;
2576
2577                 /* PORT sends FACILITY message */
2578                 case MESSAGE_FACILITY:
2579                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2580                 port_facility(portlist, message_type, param);
2581                 break;
2582
2583                 /* PORT sends DTMF message */
2584                 case MESSAGE_DTMF: /* dtmf digits received */
2585                 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);
2586                 port_dtmf(portlist, message_type, param);
2587                 break;
2588
2589                 /* PORT sends CRYPT message */
2590                 case MESSAGE_CRYPT: /* crypt response received */
2591                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2592                 port_crypt(portlist, message_type, param);
2593                 break;
2594
2595                 /* PORT sends MORE message */
2596                 case MESSAGE_OVERLAP:
2597                 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);
2598                 if (e_state != EPOINT_STATE_OUT_SETUP) {
2599                         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);
2600                         break;
2601                 }
2602                 port_overlap(portlist, message_type, param);
2603                 break;
2604
2605                 /* PORT sends PROCEEDING message */
2606                 case MESSAGE_PROCEEDING: /* port is proceeding */
2607                 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);
2608                 if (e_state!=EPOINT_STATE_OUT_SETUP
2609                  && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2610                         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);
2611                         break;
2612                 }
2613                 port_proceeding(portlist, message_type, param);
2614                 break;
2615
2616                 /* PORT sends ALERTING message */
2617                 case MESSAGE_ALERTING:
2618                 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);
2619                 if (e_state!=EPOINT_STATE_OUT_SETUP
2620                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2621                  && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2622                         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);
2623                         break;
2624                 }
2625                 port_alerting(portlist, message_type, param);
2626                 break;
2627
2628                 /* PORT sends CONNECT message */
2629                 case MESSAGE_CONNECT:
2630                 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);
2631                 if (e_state!=EPOINT_STATE_OUT_SETUP
2632                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2633                  && e_state!=EPOINT_STATE_OUT_PROCEEDING
2634                  && e_state!=EPOINT_STATE_OUT_ALERTING) {
2635                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2636                         break;
2637                 }
2638                 port_connect(portlist, message_type, param);
2639                 break;
2640
2641                 /* PORT sends DISCONNECT message */
2642                 case MESSAGE_DISCONNECT: /* port is disconnected */
2643                 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);
2644                 port_disconnect_release(portlist, message_type, param);
2645                 break;
2646
2647                 /* PORT sends a RELEASE message */
2648                 case MESSAGE_RELEASE: /* port releases */
2649                 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);
2650                 /* portlist is release at port_disconnect_release, thanx Paul */
2651                 port_disconnect_release(portlist, message_type, param);
2652                 break;
2653
2654                 /* PORT sends a TIMEOUT message */
2655                 case MESSAGE_TIMEOUT:
2656                 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);
2657                 port_timeout(portlist, message_type, param);
2658                 break; /* release */
2659
2660                 /* PORT sends a NOTIFY message */
2661                 case MESSAGE_NOTIFY:
2662                 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);
2663                 port_notify(portlist, message_type, param);
2664                 break;
2665
2666                 /* PORT sends a SUSPEND message */
2667                 case MESSAGE_SUSPEND:
2668                 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);
2669                 port_suspend(portlist, message_type, param);
2670                 break; /* suspend */
2671
2672                 /* PORT sends a RESUME message */
2673                 case MESSAGE_RESUME:
2674                 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);
2675                 port_resume(portlist, message_type, param);
2676                 break;
2677
2678 #if 0
2679                 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2680                 /* port assigns bchannel */
2681                 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2682                 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);
2683                 /* only one port is expected to be connected to bchannel */
2684                 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2685                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2686                 break;
2687 #endif
2688
2689
2690                 default:
2691                 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);
2692         }
2693
2694         /* Note: this endpoint may be destroyed, so we MUST return */
2695 }
2696
2697
2698 /* messages from join
2699  */
2700 /* join MESSAGE_CRYPT */
2701 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2702 {
2703         switch(param->crypt.type) {
2704                 /* message from remote port to "crypt manager" */
2705                 case CU_ACTK_REQ:           /* activate key-exchange */
2706                 case CU_ACTS_REQ:            /* activate shared key */
2707                 case CU_DACT_REQ:          /* deactivate */
2708                 case CU_INFO_REQ:         /* request last info message */
2709                 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2710                 break;
2711
2712                 /* message from "crypt manager" to user */
2713                 case CU_ACTK_CONF:          /* key-echange done */
2714                 case CU_ACTS_CONF:          /* shared key done */
2715                 case CU_DACT_CONF:           /* deactivated */
2716                 case CU_DACT_IND:           /* deactivated */
2717                 case CU_ERROR_IND:         /* receive error message */
2718                 case CU_INFO_IND:         /* receive info message */
2719                 case CU_INFO_CONF:         /* receive info message */
2720                 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2721                 break;
2722
2723                 default:
2724                 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);
2725         }
2726 }
2727
2728 /* join MESSAGE_INFORMATION */
2729 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2730 {
2731         struct lcr_msg *message;
2732
2733         e_overlap = 1;
2734
2735         while(portlist) {
2736                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2737                 memcpy(&message->param.information, &param->information, sizeof(struct dialing_info));
2738                 message_put(message);
2739                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2740                 portlist = portlist->next;
2741         }
2742 }
2743
2744 /* join MESSAGE_FACILITY */
2745 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2746 {
2747         struct lcr_msg *message;
2748
2749         if (!e_ext.facility && e_ext.number[0]) {
2750                 return;
2751         }
2752
2753         while(portlist) {
2754                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2755                 memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2756                 message_put(message);
2757                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2758                 portlist = portlist->next;
2759         }
2760 }
2761
2762 /* join MESSAGE_MORE */
2763 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2764 {
2765         struct lcr_msg *message;
2766
2767         new_state(EPOINT_STATE_IN_OVERLAP);
2768         
2769         /* own dialtone */
2770         if (e_join_pattern && e_ext.own_setup) {
2771                 /* disconnect audio */
2772                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2773                 message->param.audiopath = 0;
2774                 message_put(message);
2775         }
2776         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2777                         if (e_dialinginfo.id[0])
2778                                 set_tone(portlist, "dialing");
2779                         else
2780                                 set_tone(portlist, "dialtone");
2781                         return;
2782         }
2783         if (e_dialinginfo.id[0]) {
2784                 set_tone(portlist, "dialing");
2785         } else {
2786                 if (e_ext.number[0])
2787                         set_tone(portlist, "dialpbx");
2788                 else
2789                         set_tone(portlist, "dialtone");
2790         }
2791 }
2792
2793 /* join MESSAGE_PROCEEDING */
2794 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2795 {
2796         struct lcr_msg *message;
2797
2798         new_state(EPOINT_STATE_IN_PROCEEDING);
2799
2800         /* own proceeding tone */
2801         if (e_join_pattern) {
2802                 /* connect / disconnect audio */
2803                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2804                 if (e_ext.own_proceeding)
2805                         message->param.audiopath = 0;
2806                 else
2807                         message->param.audiopath = 1;
2808                 message_put(message);
2809         }
2810 //                      UCPY(e_join_tone, "proceeding");
2811         if (portlist) {
2812                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2813                 message_put(message);
2814                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2815         }
2816         set_tone(portlist, "proceeding");
2817 }
2818
2819 /* join MESSAGE_ALERTING */
2820 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2821 {
2822         struct lcr_msg *message;
2823
2824         new_state(EPOINT_STATE_IN_ALERTING);
2825
2826         /* own alerting tone */
2827         if (e_join_pattern) {
2828                 /* connect / disconnect audio */
2829                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2830                 if (e_ext.own_alerting)
2831                         message->param.audiopath = 0;
2832                 else
2833                         message->param.audiopath = 1;
2834                 message_put(message);
2835         }
2836         if (portlist) {
2837                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2838                 message_put(message);
2839                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2840         }
2841         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2842                 set_tone(portlist, "ringing");
2843                 return;
2844         }
2845         if (e_ext.number[0])
2846                 set_tone(portlist, "ringpbx");
2847         else
2848                 set_tone(portlist, "ringing");
2849
2850         if (e_ext.number[0])
2851                 e_dtmf = 1; /* allow dtmf */
2852 }
2853
2854 /* join MESSAGE_CONNECT */
2855 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2856 {
2857         struct lcr_msg *message;
2858         time_t now;
2859
2860         new_state(EPOINT_STATE_CONNECT);
2861 //                      UCPY(e_join_tone, "");
2862 //                      
2863         if (e_ext.number[0])
2864                 e_dtmf = 1; /* allow dtmf */
2865
2866         e_powerdial_on = 0;
2867         unsched_timer(&e_powerdial_timeout);
2868         memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_callerinfo));
2869         if(portlist) {
2870                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2871                 memcpy(&message->param, param, sizeof(union parameter));
2872
2873                 /* screen clip if prefix is required */
2874                 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2875                         SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2876                         SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2877                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2878                 }
2879
2880                 /* use internal caller id */
2881                 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2882                         SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2883                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2884                 }
2885
2886                 /* handle restricted caller ids */
2887                 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);
2888                 /* display callerid if desired for extension */
2889                 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));
2890
2891                 /* use conp, if enabld */
2892 //              if (!e_ext.centrex)
2893 //                      message->param.connectinfo.name[0] = '\0';
2894
2895                 /* send connect */
2896                 message_put(message);
2897                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2898         }
2899         set_tone(portlist, NULL);
2900         e_join_pattern = 0;
2901         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2902         message->param.audiopath = 1;
2903         message_put(message);
2904         time(&now);
2905         e_start = now;
2906 }
2907
2908 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2909 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2910 {
2911         char cause[16];
2912         struct lcr_msg *message;
2913         struct port_list *portlist = NULL;
2914         time_t now;
2915
2916
2917         /* be sure that we are active */
2918         notify_active();
2919         e_tx_state = NOTIFY_STATE_ACTIVE;
2920
2921         /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2922         if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2923                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2924
2925                 /* set time for power dialing */
2926                 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2927                 e_powercount++;
2928
2929                 /* set redial tone */
2930                 if (ea_endpoint->ep_portlist) {
2931                         e_join_pattern = 0;
2932                 }
2933                 set_tone(ea_endpoint->ep_portlist, "redial");
2934                 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);
2935                 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2936                 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2937                         new_state(EPOINT_STATE_IN_PROCEEDING);
2938                         if (ea_endpoint->ep_portlist) {
2939                                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2940                                 message_put(message);
2941                                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2942                         }
2943 /* caused the error, that the first knock sound was not there */
2944 /*                                      set_tone(portlist, "proceeding"); */
2945                 }
2946                 /* send display of powerdialing */
2947                 if (e_ext.display_dialing) {
2948                         portlist = ea_endpoint->ep_portlist;
2949                         while (portlist) {
2950                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2951                                 if (e_powerlimit)
2952                                         SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2953                                 else
2954                                         SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2955                                 message_put(message);
2956                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2957                                 portlist = portlist->next;
2958                         }
2959                 }
2960                 return;
2961         }
2962
2963         /* set stop time */
2964         time(&now);
2965         e_stop = now;
2966
2967         if ((e_state!=EPOINT_STATE_CONNECT
2968           && e_state!=EPOINT_STATE_OUT_DISCONNECT
2969           && e_state!=EPOINT_STATE_IN_OVERLAP
2970           && e_state!=EPOINT_STATE_IN_PROCEEDING
2971           && e_state!=EPOINT_STATE_IN_ALERTING)
2972          || !ea_endpoint->ep_portlist) { /* or no port */
2973                 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2974                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2975                 return; /* must exit here */
2976         }
2977         /* save cause */
2978         if (!e_join_cause) {
2979                 e_join_cause = param->disconnectinfo.cause;
2980                 e_join_location = param->disconnectinfo.location;
2981         }
2982
2983         /* on release we need the audio again! */
2984         if (message_type == MESSAGE_RELEASE) {
2985                 e_join_pattern = 0;
2986                 ea_endpoint->ep_join_id = 0;
2987         }
2988         /* disconnect and select tone */
2989         new_state(EPOINT_STATE_OUT_DISCONNECT);
2990         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2991         /* if own_cause, we must release the join */
2992         if (e_ext.own_cause /* own cause */
2993          || !e_join_pattern) { /* no patterns */
2994                 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);
2995                 if (message_type != MESSAGE_RELEASE)
2996                         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2997                 e_join_pattern = 0;
2998         } else { /* else we enable audio */
2999                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3000                 message->param.audiopath = 1;
3001                 message_put(message);
3002         }
3003         /* send disconnect message */
3004         SCPY(e_tone, cause);
3005         portlist = ea_endpoint->ep_portlist;
3006         while(portlist) {
3007                 set_tone(portlist, cause);
3008                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3009                 portlist = portlist->next;
3010         }
3011 }
3012
3013 /* join MESSAGE_SETUP */
3014 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3015 {
3016         struct lcr_msg *message;
3017 //      struct interface        *interface;
3018
3019         /* if we already in setup state, we just update the dialing with new digits */
3020         if (e_state == EPOINT_STATE_OUT_SETUP
3021          || e_state == EPOINT_STATE_OUT_OVERLAP) {
3022                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3023                 /* if digits changed, what we have already dialed */
3024                 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3025                         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);
3026                         /* release all ports */
3027                         while((portlist = ea_endpoint->ep_portlist)) {
3028                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3029                                 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3030                                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3031                                 message_put(message);
3032                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3033                                 ea_endpoint->free_portlist(portlist);
3034                         }
3035
3036                         /* disconnect audio */
3037                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3038                         message->param.audiopath = 0;
3039                         message_put(message);
3040
3041                         /* get dialing info */
3042                         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3043                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3044                         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3045                         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3046                         new_state(EPOINT_STATE_OUT_OVERLAP);
3047
3048                         /* get time */
3049                         schedule_timer(&e_redial_timeout, 1, 0);
3050                         return;
3051                 }
3052                 /* if we have a pending redial, so we just adjust the dialing number */
3053                 if (e_redial_timeout.active) {
3054                         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);
3055                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3056                         return;
3057                 }
3058                 if (!ea_endpoint->ep_portlist) {
3059                         PERROR("ERROR: overlap dialing to a NULL port relation\n");
3060                 }
3061                 if (ea_endpoint->ep_portlist->next) {
3062                         PERROR("ERROR: overlap dialing to a port_list port relation\n");
3063                 }
3064                 if (e_state == EPOINT_STATE_OUT_SETUP) {
3065                         /* queue digits */
3066                         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);
3067                         SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3068                         
3069                 } else {
3070                         /* get what we have not dialed yet */
3071                         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));
3072                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3073                         SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3074                         message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3075                         message_put(message);
3076                         logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3077                 }
3078                 /* always store what we have dialed or queued */
3079                 memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3080                 
3081                 return;
3082         }
3083         if (e_state != EPOINT_STATE_IDLE) {
3084                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3085                 return;
3086         }
3087         /* if an internal extension is dialed, copy that number */
3088         if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3089                 SCPY(e_ext.number, param->setup.dialinginfo.id);
3090         /* if an internal extension is dialed, get extension's info about caller */
3091         if (e_ext.number[0]) {
3092                 if (!read_extension(&e_ext, e_ext.number)) {
3093                         e_ext.number[0] = '\0';
3094                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3095                 }
3096         }
3097
3098         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3099         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3100         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3101         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3102
3103         /* process (voice over) data calls */
3104         if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3105                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3106                 memset(&e_capainfo, 0, sizeof(e_capainfo));
3107                 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3108                 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3109                 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3110         }
3111
3112         new_state(EPOINT_STATE_OUT_SETUP);
3113         /* call special setup routine */
3114         out_setup();
3115 }
3116
3117 /* join MESSAGE_mISDNSIGNAL */
3118 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3119 {
3120         struct lcr_msg *message;
3121
3122         while(portlist) {
3123                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3124                 memcpy(&message->param, param, sizeof(union parameter));
3125                 message_put(message);
3126                 portlist = portlist->next;
3127         }
3128 }
3129
3130 /* join MESSAGE_NOTIFY */
3131 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3132 {
3133         struct lcr_msg *message;
3134         int new_state;
3135
3136         if (param->notifyinfo.notify) {
3137                 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3138 //              /* if notification was generated locally, we turn hold music on/off */ 
3139 //              if (param->notifyinfo.local)
3140 // 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)
3141                 {
3142                         if (e_hold) {
3143                                 /* unhold if */
3144                                 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3145                                         if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3146                                                 while(portlist) {
3147                                                         set_tone(portlist, "");
3148                                                         portlist = portlist->next;
3149                                                 }
3150                                         }
3151                                         portlist = ea_endpoint->ep_portlist;
3152                                         e_hold = 0;
3153                                 }
3154                         } else {
3155                                 /* hold if */
3156                                 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3157                                         while(portlist) {
3158                                                 set_tone(portlist, "hold");
3159                                                 portlist = portlist->next;
3160                                         }
3161                                         portlist = ea_endpoint->ep_portlist;
3162                                         e_hold = 1;
3163                                 }
3164                         }
3165                 }
3166                 /* save new state */
3167                 e_tx_state = new_state;
3168         }
3169
3170         /* notify port(s) about it */
3171         while(portlist) {
3172                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3173                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
3174                 /* handle restricted caller ids */
3175                 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3176                 /* display callerid if desired for extension */
3177                 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));
3178                 message_put(message);
3179                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3180                 portlist = portlist->next;
3181         }
3182 }
3183
3184 /* JOIN sends messages to the endpoint
3185  */
3186 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3187 {
3188         struct port_list *portlist;
3189         struct lcr_msg *message;
3190
3191         if (!join_id) {
3192                 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3193                 return;
3194         }
3195
3196         portlist = ea_endpoint->ep_portlist;
3197
3198         /* send MESSAGE_DATA to port */
3199         if (message_type == MESSAGE_DATA) {
3200                 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3201                         /* skip if no port relation */
3202                         if (!portlist)
3203                                 return;
3204                         /* skip if more than one port relation */
3205                         if (portlist->next)
3206                                 return;
3207                         /* forward audio data to port */
3208                         message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3209                         return;
3210                 }
3211         }
3212
3213 //      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);
3214         switch(message_type) {
3215                 /* JOIN SENDS TONE message */
3216                 case MESSAGE_TONE:
3217                 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);
3218                 set_tone(portlist, param->tone.name);
3219                 break;
3220
3221                 /* JOIN SENDS CRYPT message */
3222                 case MESSAGE_CRYPT:
3223                 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);
3224                 join_crypt(portlist, message_type, param);
3225                 break;
3226
3227                 /* JOIN sends INFORMATION message */
3228                 case MESSAGE_INFORMATION:
3229                 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);
3230                 join_information(portlist, message_type, param);
3231                 break;
3232
3233                 /* JOIN sends FACILITY message */
3234                 case MESSAGE_FACILITY:
3235                 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);
3236                 join_facility(portlist, message_type, param);
3237                 break;
3238
3239                 /* JOIN sends OVERLAP message */
3240                 case MESSAGE_OVERLAP:
3241                 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);
3242                 if (e_state!=EPOINT_STATE_IN_SETUP
3243                  && e_state!=EPOINT_STATE_IN_OVERLAP) {
3244                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3245                         break;
3246                 }
3247                 join_overlap(portlist, message_type, param);
3248                 break;
3249
3250                 /* JOIN sends PROCEEDING message */
3251                 case MESSAGE_PROCEEDING:
3252                 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);
3253                 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3254                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3255                         break;
3256                 }
3257                 join_proceeding(portlist, message_type, param);
3258                 break;
3259
3260                 /* JOIN sends ALERTING message */
3261                 case MESSAGE_ALERTING:
3262                 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);
3263                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3264                  && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3265                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3266                         break;
3267                 }
3268                 join_alerting(portlist, message_type, param);
3269                 break;
3270
3271                 /* JOIN sends CONNECT message */
3272                 case MESSAGE_CONNECT:
3273                 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);
3274                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3275                  && e_state!=EPOINT_STATE_IN_PROCEEDING
3276                  && e_state!=EPOINT_STATE_IN_ALERTING) {
3277                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3278                         break;
3279                 }
3280                 join_connect(portlist, message_type, param);
3281                 break;
3282
3283                 /* JOIN sends DISCONNECT/RELEASE message */
3284                 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3285                 case MESSAGE_RELEASE: /* JOIN releases */
3286                 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);
3287                 join_disconnect_release(message_type, param);
3288                 break;
3289
3290                 /* JOIN sends SETUP message */
3291                 case MESSAGE_SETUP:
3292                 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);
3293                 join_setup(portlist, message_type, param);
3294                 break;
3295
3296                 /* JOIN sends special mISDNSIGNAL message */
3297                 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3298                 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);
3299                 join_mISDNsignal(portlist, message_type, param);
3300                 break;
3301
3302 #if 0
3303                 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3304                 /* JOIN requests bchannel */
3305                 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3306                 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);
3307                 /* only one port is expected to be connected to bchannel */
3308                 if (!portlist)
3309                         break;
3310                 if (portlist->next)
3311                         break;
3312                 e_join_pattern = 1;
3313                 SCPY(e_tone, "");
3314                 set_tone(portlist, NULL);
3315                 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3316                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3317                 break;
3318 #endif
3319
3320                 /* JOIN has pattern available */
3321                 case MESSAGE_PATTERN: /* indicating pattern available */
3322                 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);
3323                 if (!e_join_pattern) {
3324                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3325                         e_join_pattern = 1;
3326                         SCPY(e_tone, "");
3327                         while(portlist) {
3328                                 set_tone(portlist, NULL);
3329                                 portlist = portlist->next;
3330                         }
3331                         /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3332                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3333                         message->param.audiopath = 1;
3334                         message_put(message);
3335                 }
3336                 break;
3337
3338                 /* JOIN has no pattern available */
3339                 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3340                 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);
3341                 if (e_join_pattern) {
3342                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3343                         e_join_pattern = 0;
3344                         /* disconnect our audio tx and rx */
3345                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3346                         message->param.audiopath = 0;
3347                         message_put(message);
3348                 }
3349                 break;
3350
3351 #if 0
3352                 /* JOIN (dunno at the moment) */
3353                 case MESSAGE_REMOTE_AUDIO:
3354                 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);
3355                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3356                 message->param.audiopath = param->channel;
3357                 message_put(message);
3358                 break;
3359 #endif
3360
3361                 /* JOIN sends a notify message */
3362                 case MESSAGE_NOTIFY:
3363                 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);
3364                 join_notify(portlist, message_type, param);
3365                 break;
3366
3367                 /* JOIN wants keypad / dtmf */
3368                 case MESSAGE_ENABLEKEYPAD:
3369                 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);
3370                 e_enablekeypad = 1;
3371                 e_dtmf = 1;
3372                 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3373                 end_trace();
3374                 break;
3375
3376                 default:
3377                 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);
3378         }
3379 }
3380
3381
3382 /* pick_join will connect the first incoming call found. the endpoint
3383  * will receivce a MESSAGE_CONNECT.
3384  */
3385 int match_list(char *list, char *item)
3386 {
3387         char *end, *next = NULL;
3388
3389         /* no list make matching */
3390         if (!list)
3391                 return(1);
3392
3393         while(42) {
3394                 /* eliminate white spaces */
3395                 while (*list <= ' ')
3396                         list++;
3397                 if (*list == ',') {
3398                         list++;
3399                         continue;
3400                 }
3401                 /* if end of list is reached, we return */
3402                 if (list[0] == '\0')
3403                         return(0);
3404                 /* if we have more than one entry (left) */
3405                 if ((end = strchr(list, ',')))
3406                         next = end + 1;
3407                 else
3408                         next = end = strchr(list, '\0');
3409                 while (*(end-1) <= ' ')
3410                         end--;
3411                 /* if string part matches item */
3412                 if (!strncmp(list, item, end-list))
3413                         return(1);
3414                 list = next;
3415         }
3416 }
3417
3418 void EndpointAppPBX::pick_join(char *extensions)
3419 {
3420         struct lcr_msg *message;
3421         struct port_list *portlist;
3422         class Port *port;
3423         class EndpointAppPBX *eapp, *found;
3424         class Join *join;
3425         class JoinPBX *joinpbx;
3426         struct join_relation *relation;
3427         int vbox;
3428
3429         /* find an endpoint that is ringing internally or vbox with higher priority */
3430         vbox = 0;
3431         found = NULL;
3432         eapp = apppbx_first;
3433         while(eapp) {
3434                 if (eapp!=this && ea_endpoint->ep_portlist) {
3435                         portlist = eapp->ea_endpoint->ep_portlist;
3436                         while(portlist) {
3437                                 if ((port = find_port_id(portlist->port_id))) {
3438                                         if (port->p_type == PORT_TYPE_VBOX_OUT) {
3439                                                 if (match_list(extensions, eapp->e_ext.number)) {
3440                                                         found = eapp;
3441                                                         vbox = 1;
3442                                                         break;
3443                                                 }
3444                                         }
3445                                         if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3446                                          && port->p_state==PORT_STATE_OUT_ALERTING)
3447                                                 if (match_list(extensions, eapp->e_ext.number)) {
3448                                                         found = eapp;
3449                                                 }
3450                                 }
3451                                 portlist = portlist->next;
3452                         }
3453                         if (portlist)
3454                                 break;
3455                 }
3456                 eapp = eapp->next;
3457         }
3458
3459         /* if no endpoint found */
3460         if (!found) {
3461                 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);
3462 reject:
3463                 set_tone(ea_endpoint->ep_portlist, "cause_10");
3464                 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3465                 new_state(EPOINT_STATE_OUT_DISCONNECT);
3466                 return;
3467         }
3468         eapp = found;
3469
3470         if (ea_endpoint->ep_join_id) {
3471                 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3472                 goto reject;
3473         }
3474         if (!eapp->ea_endpoint->ep_join_id) {
3475                 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3476                 goto reject;
3477         }
3478         join = find_join_id(eapp->ea_endpoint->ep_join_id);
3479         if (!join) {
3480                 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3481                 goto reject;
3482         }
3483         if (join->j_type != JOIN_TYPE_PBX) {
3484                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3485                 goto reject;
3486         }
3487         joinpbx = (class JoinPBX *)join;
3488         relation = joinpbx->j_relation;
3489         if (!relation) {
3490                 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3491                 goto reject;
3492         }
3493         while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3494                 relation = relation->next;
3495                 if (!relation) {
3496                         PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3497                         goto reject;
3498                 }
3499         }
3500
3501         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3502
3503         if (options.deb & DEBUG_EPOINT) {
3504                 class Join *debug_c = join_first;
3505                 class Endpoint *debug_e = epoint_first;
3506                 class Port *debug_p = port_first;
3507
3508                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3509
3510                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3511                 while(debug_c) {
3512                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3513                         debug_c = debug_c->next;
3514                 }
3515                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3516                 while(debug_e) {
3517                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3518                         debug_e = debug_e->next;
3519                 }
3520                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3521                 while(debug_p) {
3522                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3523                         debug_p = debug_p->next;
3524                 }
3525         }
3526
3527         /* relink join */
3528         ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3529         relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3530         eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3531
3532         /* connnecting our endpoint */
3533         new_state(EPOINT_STATE_CONNECT);
3534         if (e_ext.number[0])
3535                 e_dtmf = 1;
3536         set_tone(ea_endpoint->ep_portlist, NULL);
3537
3538         /* now we send a release to the ringing endpoint */
3539         message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3540         message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3541         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3542         message_put(message);
3543
3544         /* we send a connect to the join with our caller id */
3545         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3546         SCPY(message->param.connectinfo.id, e_callerinfo.id);
3547         message->param.connectinfo.present = e_callerinfo.present;
3548         message->param.connectinfo.screen = e_callerinfo.screen;
3549         message->param.connectinfo.itype = e_callerinfo.itype;
3550         message->param.connectinfo.ntype = e_callerinfo.ntype;
3551         message_put(message);
3552
3553         /* we send a connect to our port with the remote callerid */
3554         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3555         SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3556         message->param.connectinfo.present = eapp->e_callerinfo.present;
3557         message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3558         message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3559         message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3560         /* handle restricted caller ids */
3561         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);
3562         /* display callerid if desired for extension */
3563         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));
3564         message_put(message);
3565
3566         /* we send a connect to the audio path (not for vbox) */
3567         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3568         message->param.audiopath = 1;
3569         message_put(message);
3570
3571         /* beeing paranoid, we make call update */
3572         trigger_work(&joinpbx->j_updatebridge);
3573
3574         if (options.deb & DEBUG_EPOINT) {
3575                 class Join *debug_c = join_first;
3576                 class Endpoint *debug_e = epoint_first;
3577                 class Port *debug_p = port_first;
3578
3579                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3580
3581                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3582                 while(debug_c) {
3583                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3584                         debug_c = debug_c->next;
3585                 }
3586                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3587                 while(debug_e) {
3588                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3589                         debug_e = debug_e->next;
3590                 }
3591                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3592                 while(debug_p) {
3593                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3594                         debug_p = debug_p->next;
3595                 }
3596         }
3597 }
3598
3599
3600 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3601  */
3602 void EndpointAppPBX::join_join(void)
3603 {
3604         struct lcr_msg *message;
3605         struct join_relation *our_relation, *other_relation;
3606         struct join_relation **our_relation_pointer, **other_relation_pointer;
3607         class Join *our_join, *other_join;
3608         class JoinPBX *our_joinpbx, *other_joinpbx;
3609         class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3610         class Port *our_port, *other_port;
3611         class Pdss1 *our_pdss1, *other_pdss1;
3612
3613         /* are we a candidate to join a join? */
3614         our_join = find_join_id(ea_endpoint->ep_join_id);
3615         if (!our_join) {
3616                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3617                 return;
3618         }
3619         if (our_join->j_type != JOIN_TYPE_PBX) {
3620                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3621                 return;
3622         }
3623         our_joinpbx = (class JoinPBX *)our_join;
3624         if (!ea_endpoint->ep_portlist) {
3625                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3626                 return;
3627         }
3628         if (!e_ext.number[0]) {
3629                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3630                 return;
3631         }
3632         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3633         if (!our_port) {
3634                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3635                 return;
3636         }
3637         if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3638                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3639                 return;
3640         }
3641         our_pdss1 = (class Pdss1 *)our_port;
3642
3643         /* find an endpoint that is on hold and has the same mISDNport that we are on */
3644         other_eapp = apppbx_first;
3645         while(other_eapp) {
3646                 if (other_eapp == this) {
3647                         other_eapp = other_eapp->next;
3648                         continue;
3649                 }
3650                 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);
3651                 if (other_eapp->e_ext.number[0] /* has terminal */
3652                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3653                  && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3654                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3655                         if (other_port) { /* port still exists */
3656                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3657                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3658                                         other_pdss1 = (class Pdss1 *)other_port;
3659                                         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);
3660                                         if (other_pdss1->p_m_hold /* port is on hold */
3661                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3662                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3663                                                 break;
3664                                 } else {
3665                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3666                                 }
3667                         } else {
3668                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3669                         }
3670                 }
3671                 other_eapp = other_eapp->next;
3672         }
3673         if (!other_eapp) {
3674                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3675                 return;
3676         }
3677         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3678
3679         /* if we have the same join */
3680         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3681                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3682                 return;
3683         }
3684         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3685         if (!other_join) {
3686                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3687                 return;
3688         }
3689         if (other_join->j_type != JOIN_TYPE_PBX) {
3690                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3691                 return;
3692         }
3693         other_joinpbx = (class JoinPBX *)other_join;
3694         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3695                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3696                 return;
3697         }
3698
3699         /* remove relation to endpoint for join on hold */
3700         other_relation = other_joinpbx->j_relation;
3701         other_relation_pointer = &other_joinpbx->j_relation;
3702         while(other_relation) {
3703                 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3704                         /* detach other endpoint on hold */
3705                         *other_relation_pointer = other_relation->next;
3706                         FREE(other_relation, sizeof(struct join_relation));
3707                         cmemuse--;
3708                         other_relation = *other_relation_pointer;
3709                         other_eapp->ea_endpoint->ep_join_id = 0;
3710                         continue;
3711                 }
3712
3713                 /* change join/hold pointer of endpoint to the new join */
3714                 temp_epoint = find_epoint_id(other_relation->epoint_id);
3715                 if (temp_epoint) {
3716                         if (temp_epoint->ep_join_id == other_join->j_serial)
3717                                 temp_epoint->ep_join_id = our_join->j_serial;
3718                 }
3719
3720                 other_relation_pointer = &other_relation->next;
3721                 other_relation = other_relation->next;
3722         }
3723         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3724
3725         /* join call relations */
3726         our_relation = our_joinpbx->j_relation;
3727         our_relation_pointer = &our_joinpbx->j_relation;
3728         while(our_relation) {
3729                 our_relation_pointer = &our_relation->next;
3730                 our_relation = our_relation->next;
3731         }
3732         *our_relation_pointer = other_joinpbx->j_relation;
3733         other_joinpbx->j_relation = NULL;
3734         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3735
3736         /* release endpoint on hold */
3737         message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3738         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3739         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3740         message_put(message);
3741         
3742         /* if we are not a partyline, we get partyline state from other join */
3743         our_joinpbx->j_partyline += other_joinpbx->j_partyline; 
3744
3745         /* remove empty join */
3746         delete other_join;
3747         PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3748
3749         /* mixer must update */
3750         trigger_work(&our_joinpbx->j_updatebridge);
3751
3752         /* we send a retrieve to that endpoint */
3753         // mixer will update the hold-state of the join and send it to the endpoints is changes
3754 }
3755
3756
3757 /* check if we have an external call
3758  * this is used to check for encryption ability
3759  */
3760 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3761 {
3762         struct join_relation *relation;
3763         class Join *join;
3764         class JoinPBX *joinpbx;
3765         class Endpoint *epoint;
3766
3767         /* some paranoia check */
3768         if (!ea_endpoint->ep_portlist) {
3769                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3770                 *errstr = "No Call";
3771                 return(1);
3772         }
3773         if (!e_ext.number[0]) {
3774                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3775                 *errstr = "No Call";
3776                 return(1);
3777         }
3778
3779         /* check if we have a join with 2 parties */
3780         join = find_join_id(ea_endpoint->ep_join_id);
3781         if (!join) {
3782                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3783                 *errstr = "No Call";
3784                 return(1);
3785         }
3786         if (join->j_type != JOIN_TYPE_PBX) {
3787                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3788                 *errstr = "No PBX Call";
3789                 return(1);
3790         }
3791         joinpbx = (class JoinPBX *)join;
3792         relation = joinpbx->j_relation;
3793         if (!relation) {
3794                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3795                 *errstr = "No Call";
3796                 return(1);
3797         }
3798         if (!relation->next) {
3799                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3800                 *errstr = "No Call";
3801                 return(1);
3802         }
3803         if (relation->next->next) {
3804                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3805                 *errstr = "Err: Conference";
3806                 return(1);
3807         }
3808         if (relation->epoint_id == ea_endpoint->ep_serial) {
3809                 relation = relation->next;
3810                 if (relation->epoint_id == ea_endpoint->ep_serial) {
3811                         PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3812                         *errstr = "Software Error";
3813                         return(1);
3814                 }
3815         }
3816
3817         /* check remote port for external call */
3818         epoint = find_epoint_id(relation->epoint_id);
3819         if (!epoint) {
3820                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3821                 *errstr = "No Call";
3822                 return(1);
3823         }
3824         if (!epoint->ep_portlist) {
3825                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3826                 *errstr = "No Call";
3827                 return(1);
3828         }
3829         *port = find_port_id(epoint->ep_portlist->port_id);
3830         if (!(*port)) {
3831                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3832                 *errstr = "No Call";
3833                 return(1);
3834         }
3835         if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3836                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3837                 *errstr = "No Ext Call";
3838                 return(1);
3839         }
3840         if ((*port)->p_state != PORT_STATE_CONNECT) {
3841                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3842                 *errstr = "No Ext Connect";
3843                 return(1);
3844         }
3845         return(0);
3846 }
3847
3848 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3849 {
3850         const char *logtext = "unknown";
3851         char buffer[64];
3852
3853         switch(message_type) {
3854                 case MESSAGE_SETUP:
3855                 trace_header("SETUP", dir);
3856                 if (dir == DIRECTION_OUT)
3857                         add_trace("to", NULL, "CH(%lu)", port_id);
3858                 if (dir == DIRECTION_IN)
3859                         add_trace("from", NULL, "CH(%lu)", port_id);
3860                 if (param->setup.callerinfo.extension[0])
3861                         add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3862                 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3863                 switch(param->setup.callerinfo.present) {
3864                         case INFO_PRESENT_RESTRICTED:
3865                         add_trace("caller id", "present", "restricted");
3866                         break;
3867                         case INFO_PRESENT_ALLOWED:
3868                         add_trace("caller id", "present", "allowed");
3869                         break;
3870                         default:
3871                         add_trace("caller id", "present", "not available");
3872                 }
3873                 if (param->setup.callerinfo.ntype2) {
3874                         add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3875                         switch(param->setup.callerinfo.present) {
3876                                 case INFO_PRESENT_RESTRICTED:
3877                                 add_trace("caller id2", "present", "restricted");
3878                                 break;
3879                                 case INFO_PRESENT_ALLOWED:
3880                                 add_trace("caller id2", "present", "allowed");
3881                                 break;
3882                                 default:
3883                                 add_trace("caller id2", "present", "not available");
3884                         }
3885                 }
3886                 if (param->setup.redirinfo.id[0]) {
3887                         add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3888                         switch(param->setup.redirinfo.present) {
3889                                 case INFO_PRESENT_RESTRICTED:
3890                                 add_trace("redir'ing", "present", "restricted");
3891                                 break;
3892                                 case INFO_PRESENT_ALLOWED:
3893                                 add_trace("redir'ing", "present", "allowed");
3894                                 break;
3895                                 default:
3896                                 add_trace("redir'ing", "present", "not available");
3897                         }
3898                 }
3899                 if (param->setup.dialinginfo.id[0])
3900                         add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3901                 if (param->setup.dialinginfo.keypad[0])
3902                         add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3903                 if (param->setup.dialinginfo.display[0])
3904                         add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3905                 if (param->setup.dialinginfo.sending_complete)
3906                         add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3907                 end_trace();
3908                 break;
3909
3910                 case MESSAGE_OVERLAP:
3911                 trace_header("SETUP ACKNOWLEDGE", dir);
3912                 if (dir == DIRECTION_OUT)
3913                         add_trace("to", NULL, "CH(%lu)", port_id);
3914                 if (dir == DIRECTION_IN)
3915                         add_trace("from", NULL, "CH(%lu)", port_id);
3916                 end_trace();
3917                 break;
3918
3919                 case MESSAGE_PROCEEDING:
3920                 trace_header("PROCEEDING", dir);
3921                 if (dir == DIRECTION_OUT)
3922                         add_trace("to", NULL, "CH(%lu)", port_id);
3923                 if (dir == DIRECTION_IN)
3924                         add_trace("from", NULL, "CH(%lu)", port_id);
3925                 end_trace();
3926                 break;
3927
3928                 case MESSAGE_ALERTING:
3929                 trace_header("ALERTING", dir);
3930                 if (dir == DIRECTION_OUT)
3931                         add_trace("to", NULL, "CH(%lu)", port_id);
3932                 if (dir == DIRECTION_IN)
3933                         add_trace("from", NULL, "CH(%lu)", port_id);
3934                 end_trace();
3935                 break;
3936
3937                 case MESSAGE_CONNECT:
3938                 trace_header("CONNECT", dir);
3939                 if (dir == DIRECTION_OUT)
3940                         add_trace("to", NULL, "CH(%lu)", port_id);
3941                 if (dir == DIRECTION_IN)
3942                         add_trace("from", NULL, "CH(%lu)", port_id);
3943                 if (param->connectinfo.extension[0])
3944                         add_trace("extension", NULL, "%s", param->connectinfo.extension);
3945                 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3946                 switch(param->connectinfo.present) {
3947                         case INFO_PRESENT_RESTRICTED:
3948                         add_trace("connect id", "present", "restricted");
3949                         break;
3950                         case INFO_PRESENT_ALLOWED:
3951                         add_trace("connect id", "present", "allowed");
3952                         break;
3953                         default:
3954                         add_trace("connect id", "present", "not available");
3955                 }
3956                 if (param->connectinfo.display[0])
3957                         add_trace("display", NULL, "%s", param->connectinfo.display);
3958                 end_trace();
3959                 break;
3960
3961                 case MESSAGE_DISCONNECT:
3962                 case MESSAGE_RELEASE:
3963                 if (message_type == MESSAGE_DISCONNECT)
3964                         trace_header("DISCONNECT", dir);
3965                 else
3966                         trace_header("RELEASE", dir);
3967                 if (dir == DIRECTION_OUT)
3968                         add_trace("to", NULL, "CH(%lu)", port_id);
3969                 if (dir == DIRECTION_IN)
3970                         add_trace("from", NULL, "CH(%lu)", port_id);
3971                 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3972                 switch(param->disconnectinfo.location) {
3973                         case LOCATION_USER:
3974                         add_trace("cause", "location", "0-User");
3975                         break;
3976                         case LOCATION_PRIVATE_LOCAL:
3977                         add_trace("cause", "location", "1-Local-PBX");
3978                         break;
3979                         case LOCATION_PUBLIC_LOCAL:
3980                         add_trace("cause", "location", "2-Local-Exchange");
3981                         break;
3982                         case LOCATION_TRANSIT:
3983                         add_trace("cause", "location", "3-Transit");
3984                         break;
3985                         case LOCATION_PUBLIC_REMOTE:
3986                         add_trace("cause", "location", "4-Remote-Exchange");
3987                         break;
3988                         case LOCATION_PRIVATE_REMOTE:
3989                         add_trace("cause", "location", "5-Remote-PBX");
3990                         break;
3991                         case LOCATION_INTERNATIONAL:
3992                         add_trace("cause", "location", "7-International-Exchange");
3993                         break;
3994                         case LOCATION_BEYOND:
3995                         add_trace("cause", "location", "10-Beyond-Interworking");
3996                         break;
3997                         default:
3998                         add_trace("cause", "location", "%d", param->disconnectinfo.location);
3999                 }
4000                 if (param->disconnectinfo.display[0])
4001                         add_trace("display", NULL, "%s", param->disconnectinfo.display);
4002                 end_trace();
4003                 break;
4004
4005                 case MESSAGE_NOTIFY:
4006                 switch(param->notifyinfo.notify) {
4007                         case 0x00:
4008                         logtext = "NULL";
4009                         break;
4010                         case 0x80:
4011                         logtext = "USER_SUSPENDED";
4012                         break;
4013                         case 0x82:
4014                         logtext = "BEARER_SERVICE_CHANGED";
4015                         break;
4016                         case 0x81:
4017                         logtext = "USER_RESUMED";
4018                         break;
4019                         case 0xc2:
4020                         logtext = "CONFERENCE_ESTABLISHED";
4021                         break;
4022                         case 0xc3:
4023                         logtext = "CONFERENCE_DISCONNECTED";
4024                         break;
4025                         case 0xc4:
4026                         logtext = "OTHER_PARTY_ADDED";
4027                         break;
4028                         case 0xc5:
4029                         logtext = "ISOLATED";
4030                         break;
4031                         case 0xc6:
4032                         logtext = "REATTACHED";
4033                         break;
4034                         case 0xc7:
4035                         logtext = "OTHER_PARTY_ISOLATED";
4036                         break;
4037                         case 0xc8:
4038                         logtext = "OTHER_PARTY_REATTACHED";
4039                         break;
4040                         case 0xc9:
4041                         logtext = "OTHER_PARTY_SPLIT";
4042                         break;
4043                         case 0xca:
4044                         logtext = "OTHER_PARTY_DISCONNECTED";
4045                         break;
4046                         case 0xcb:
4047                         logtext = "CONFERENCE_FLOATING";
4048                         break;
4049                         case 0xcc:
4050                         logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4051                         break;
4052                         case 0xcf:
4053                         logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4054                         break;
4055                         case 0xe0:
4056                         logtext = "CALL_IS_A_WAITING_CALL";
4057                         break;
4058                         case 0xe8:
4059                         logtext = "DIVERSION_ACTIVATED";
4060                         break;
4061                         case 0xe9:
4062                         logtext = "RESERVED_CT_1";
4063                         break;
4064                         case 0xea:
4065                         logtext = "RESERVED_CT_2";
4066                         break;
4067                         case 0xee:
4068                         logtext = "REVERSE_CHARGING";
4069                         break;
4070                         case 0xf9:
4071                         logtext = "REMOTE_HOLD";
4072                         break;
4073                         case 0xfa:
4074                         logtext = "REMOTE_RETRIEVAL";
4075                         break;
4076                         case 0xfb:
4077                         logtext = "CALL_IS_DIVERTING";
4078                         break;
4079                         default:
4080                         SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4081                         logtext = buffer;
4082
4083                 }
4084                 trace_header("NOTIFY", dir);
4085                 if (dir == DIRECTION_OUT)
4086                         add_trace("to", NULL, "CH(%lu)", port_id);
4087                 if (dir == DIRECTION_IN)
4088                         add_trace("from", NULL, "CH(%lu)", port_id);
4089                 if (param->notifyinfo.notify)
4090                         add_trace("indicator", NULL, "%s", logtext);
4091                 if (param->notifyinfo.id[0]) {
4092                         add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4093                         switch(param->notifyinfo.present) {
4094                                 case INFO_PRESENT_RESTRICTED:
4095                                 add_trace("redir'on", "present", "restricted");
4096                                 break;
4097                                 case INFO_PRESENT_ALLOWED:
4098                                 add_trace("redir'on", "present", "allowed");
4099                                 break;
4100                                 default:
4101                                 add_trace("redir'on", "present", "not available");
4102                         }
4103                 }
4104                 if (param->notifyinfo.display[0])
4105                         add_trace("display", NULL, "%s", param->notifyinfo.display);
4106                 end_trace();
4107                 break;
4108
4109                 case MESSAGE_INFORMATION:
4110                 trace_header("INFORMATION", dir);
4111                 if (dir == DIRECTION_OUT)
4112                         add_trace("to", NULL, "CH(%lu)", port_id);
4113                 if (dir == DIRECTION_IN)
4114                         add_trace("from", NULL, "CH(%lu)", port_id);
4115                 if (param->information.id[0])
4116                         add_trace("dialing", NULL, "%s", param->information.id);
4117                 if (param->information.display[0])
4118                         add_trace("display", NULL, "%s", param->information.display);
4119                 if (param->information.sending_complete)
4120                         add_trace("complete", NULL, "true", param->information.sending_complete);
4121                 end_trace();
4122                 break;
4123
4124                 case MESSAGE_FACILITY:
4125                 trace_header("FACILITY", dir);
4126                 if (dir == DIRECTION_OUT)
4127                         add_trace("to", NULL, "CH(%lu)", port_id);
4128                 if (dir == DIRECTION_IN)
4129                         add_trace("from", NULL, "CH(%lu)", port_id);
4130                 end_trace();
4131                 break;
4132
4133                 case MESSAGE_TONE:
4134                 trace_header("TONE", dir);
4135                 if (dir == DIRECTION_OUT)
4136                         add_trace("to", NULL, "CH(%lu)", port_id);
4137                 if (dir == DIRECTION_IN)
4138                         add_trace("from", NULL, "CH(%lu)", port_id);
4139                 if (param->tone.name[0]) {
4140                         add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4141                         add_trace("name", NULL, "%s", param->tone.name);
4142                 } else
4143                         add_trace("off", NULL, NULL);
4144                 end_trace();
4145                 break;
4146
4147                 case MESSAGE_SUSPEND:
4148                 case MESSAGE_RESUME:
4149                 if (message_type == MESSAGE_SUSPEND)
4150                         trace_header("SUSPEND", dir);
4151                 else
4152                         trace_header("RESUME", dir);
4153                 if (dir == DIRECTION_OUT)
4154                         add_trace("to", NULL, "CH(%lu)", port_id);
4155                 if (dir == DIRECTION_IN)
4156                         add_trace("from", NULL, "CH(%lu)", port_id);
4157                 if (param->parkinfo.len)
4158                         add_trace("length", NULL, "%d", param->parkinfo.len);
4159                 end_trace();
4160                 break;
4161
4162 #if 0
4163                 case MESSAGE_BCHANNEL:
4164                 trace_header("BCHANNEL", dir);
4165                 switch(param->bchannel.type) {
4166                         case BCHANNEL_REQUEST:
4167                         add_trace("type", NULL, "request");
4168                         break;
4169                         case BCHANNEL_ASSIGN:
4170                         add_trace("type", NULL, "assign");
4171                         break;
4172                         case BCHANNEL_ASSIGN_ACK:
4173                         add_trace("type", NULL, "assign_ack");
4174                         break;
4175                         case BCHANNEL_REMOVE:
4176                         add_trace("type", NULL, "remove");
4177                         break;
4178                         case BCHANNEL_REMOVE_ACK:
4179                         add_trace("type", NULL, "remove_ack");
4180                         break;
4181                 }
4182                 if (param->bchannel.addr)
4183                         add_trace("address", NULL, "%x", param->bchannel.addr);
4184                 end_trace();
4185                 break;
4186 #endif
4187
4188                 default:
4189                 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4190         }
4191 }
4192
4193 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4194 {
4195         struct lcr_msg *message;
4196
4197         if (!portlist)
4198                 return;
4199         if (!portlist->port_id)
4200                 return;
4201
4202         if (!e_connectedmode) {
4203                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4204                 message->param.disconnectinfo.cause = cause;
4205                 message->param.disconnectinfo.location = location;
4206                 if (display[0])
4207                         SCPY(message->param.disconnectinfo.display, display);
4208                 else
4209                         SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4210         } else {
4211                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4212                 if (display[0])
4213                         SCPY(message->param.notifyinfo.display, display);
4214                 else
4215                         SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4216         }
4217         message_put(message);
4218         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
4219 }
4220