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