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