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