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