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