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