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