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