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