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