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