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