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