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