fixed dialtone bug
[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.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                         if (e_dialinginfo.id[0])
2881                                 set_tone(portlist, "dialing");
2882                         else
2883                                 set_tone(portlist, "dialtone");
2884                         return;
2885         }
2886         if (e_ext.number[0])
2887                 set_tone(portlist, "dialpbx");
2888         else
2889                 set_tone(portlist, "dialtone");
2890 }
2891
2892 /* join MESSAGE_PROCEEDING */
2893 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2894 {
2895         struct message *message;
2896
2897         new_state(EPOINT_STATE_IN_PROCEEDING);
2898
2899         /* own proceeding tone */
2900         if (e_join_pattern)
2901         {
2902                 /* connect / disconnect audio */
2903                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2904                 if (e_ext.own_proceeding)
2905                         message->param.audiopath = CHANNEL_STATE_HOLD;
2906                 else
2907                         message->param.audiopath = CHANNEL_STATE_CONNECT;
2908                 message_put(message);
2909         }
2910 //                      UCPY(e_join_tone, "proceeding");
2911         if (portlist)
2912         {
2913                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2914                 message_put(message);
2915                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2916         }
2917         set_tone(portlist, "proceeding");
2918 }
2919
2920 /* join MESSAGE_ALERTING */
2921 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2922 {
2923         struct message *message;
2924
2925         new_state(EPOINT_STATE_IN_ALERTING);
2926
2927         /* own alerting tone */
2928         if (e_join_pattern)
2929         {
2930                 /* connect / disconnect audio */
2931                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2932                 if (e_ext.own_alerting)
2933                         message->param.audiopath = CHANNEL_STATE_HOLD;
2934                 else
2935                         message->param.audiopath = CHANNEL_STATE_CONNECT;
2936                 message_put(message);
2937         }
2938         if (portlist)
2939         {
2940                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2941                 message_put(message);
2942                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2943         }
2944         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
2945         {
2946                 set_tone(portlist, "ringing");
2947                 return;
2948         }
2949         if (e_ext.number[0])
2950                 set_tone(portlist, "ringpbx");
2951         else
2952                 set_tone(portlist, "ringing");
2953 }
2954
2955 /* join MESSAGE_CONNECT */
2956 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2957 {
2958         struct message *message;
2959
2960         new_state(EPOINT_STATE_CONNECT);
2961 //                      UCPY(e_join_tone, "");
2962         if (e_ext.number[0])
2963                 e_dtmf = 1; /* allow dtmf */
2964         e_powerdialing = 0;
2965         memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_callerinfo));
2966         if(portlist)
2967         {
2968                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2969                 memcpy(&message->param, param, sizeof(union parameter));
2970
2971                 /* screen clip if prefix is required */
2972                 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0])
2973                 {
2974                         SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2975                         SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype));
2976                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2977                 }
2978
2979                 /* use internal caller id */
2980                 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore))
2981                 {
2982                         SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2983                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2984                 }
2985
2986                 /* handle restricted caller ids */
2987                 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);
2988                 /* display callerid if desired for extension */
2989                 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));
2990
2991                 /* use conp, if enabld */
2992 //              if (!e_ext.centrex)
2993 //                      message->param.connectinfo.name[0] = '\0';
2994
2995                 /* send connect */
2996                 message_put(message);
2997                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2998         }
2999         set_tone(portlist, NULL);
3000         e_join_pattern = 0;
3001         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3002         message->param.audiopath = CHANNEL_STATE_CONNECT;
3003         message_put(message);
3004         e_start = now;
3005 }
3006
3007 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3008 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3009 {
3010         char cause[16];
3011         struct message *message;
3012         struct port_list *portlist = NULL;
3013
3014
3015         /* be sure that we are active */
3016         notify_active();
3017         e_tx_state = NOTIFY_STATE_ACTIVE;
3018
3019         /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
3020         if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1))
3021         {
3022                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
3023
3024                 /* set time for power dialing */
3025                 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
3026                 e_powercount++;
3027
3028                 /* set redial tone */
3029                 if (ea_endpoint->ep_portlist)
3030                 {
3031                         e_join_pattern = 0;
3032                 }
3033                 set_tone(ea_endpoint->ep_portlist, "redial");
3034                 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);
3035                 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3036                 if (e_state==EPOINT_STATE_IN_OVERLAP)
3037                 {
3038                         new_state(EPOINT_STATE_IN_PROCEEDING);
3039                         if (ea_endpoint->ep_portlist)
3040                         {
3041                                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3042                                 message_put(message);
3043                                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3044                         }
3045 /* caused the error, that the first knock sound was not there */
3046 /*                                      set_tone(portlist, "proceeding"); */
3047                 }
3048                 /* send display of powerdialing */
3049                 if (e_ext.display_dialing)
3050                 {
3051                         portlist = ea_endpoint->ep_portlist;
3052                         while (portlist)
3053                         {
3054                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3055                                 if (e_powerlimit)
3056                                         SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3057                                 else
3058                                         SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3059                                 message_put(message);
3060                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3061                                 portlist = portlist->next;
3062                         }
3063                 }
3064                 return;
3065         }
3066
3067         /* set stop time */
3068         e_stop = now;
3069
3070         if ((e_state!=EPOINT_STATE_CONNECT
3071           && e_state!=EPOINT_STATE_OUT_DISCONNECT
3072           && e_state!=EPOINT_STATE_IN_OVERLAP
3073           && e_state!=EPOINT_STATE_IN_PROCEEDING
3074           && e_state!=EPOINT_STATE_IN_ALERTING)
3075          || !ea_endpoint->ep_portlist) /* or no port */
3076         {
3077                 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3078                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */
3079                 return; /* must exit here */
3080         }
3081         /* save cause */
3082         if (!e_join_cause)
3083         {
3084                 e_join_cause = param->disconnectinfo.cause;
3085                 e_join_location = param->disconnectinfo.location;
3086         }
3087
3088         /* on release we need the audio again! */
3089         if (message_type == MESSAGE_RELEASE)
3090         {
3091                 e_join_pattern = 0;
3092                 ea_endpoint->ep_join_id = 0;
3093         }
3094         /* disconnect and select tone */
3095         new_state(EPOINT_STATE_OUT_DISCONNECT);
3096         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3097         /* if own_cause, we must release the join */
3098         if (e_ext.own_cause /* own cause */
3099          || !e_join_pattern) /* no patterns */
3100         {
3101                 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);
3102                 if (message_type != MESSAGE_RELEASE)
3103                         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
3104                 e_join_pattern = 0;
3105         } else /* else we enable audio */
3106         {
3107                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3108                 message->param.audiopath = CHANNEL_STATE_CONNECT;
3109                 message_put(message);
3110         }
3111         /* send disconnect message */
3112         SCPY(e_tone, cause);
3113         portlist = ea_endpoint->ep_portlist;
3114         while(portlist)
3115         {
3116                 set_tone(portlist, cause);
3117                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3118                 portlist = portlist->next;
3119         }
3120 }
3121
3122 /* join MESSAGE_SETUP */
3123 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3124 {
3125         struct message *message;
3126 //      struct interface        *interface;
3127
3128         /* if we already in setup state, we just update the dialing with new digits */
3129         if (e_state == EPOINT_STATE_OUT_SETUP
3130          || e_state == EPOINT_STATE_OUT_OVERLAP)
3131         {
3132                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3133                 /* if digits changed, what we have already dialed */
3134                 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id)))
3135                 {
3136                         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);
3137                         /* release all ports */
3138                         while((portlist = ea_endpoint->ep_portlist))
3139                         {
3140                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3141                                 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3142                                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3143                                 message_put(message);
3144                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3145                                 ea_endpoint->free_portlist(portlist);
3146                         }
3147
3148                         /* disconnect audio */
3149                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3150                         message->param.audiopath = CHANNEL_STATE_HOLD;
3151                         message_put(message);
3152
3153                         /* get dialing info */
3154                         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3155                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3156                         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3157                         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3158                         new_state(EPOINT_STATE_OUT_OVERLAP);
3159
3160                         /* get time */
3161                         e_redial = now_d + 1; /* set redial one second in the future */
3162                         return;
3163                 }
3164                 /* if we have a pending redial, so we just adjust the dialing number */
3165                 if (e_redial)
3166                 {
3167                         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);
3168                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3169                         return;
3170                 }
3171                 if (!ea_endpoint->ep_portlist)
3172                 {
3173                         PERROR("ERROR: overlap dialing to a NULL port relation\n");
3174                 }
3175                 if (ea_endpoint->ep_portlist->next)
3176                 {
3177                         PERROR("ERROR: overlap dialing to a port_list port relation\n");
3178                 }
3179                 if (e_state == EPOINT_STATE_OUT_SETUP)
3180                 {
3181                         /* queue digits */
3182                         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);
3183                         SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3184                         
3185                 } else
3186                 {
3187                         /* get what we have not dialed yet */
3188                         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));
3189                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3190                         SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3191                         message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3192                         message_put(message);
3193                         logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3194                 }
3195                 /* always store what we have dialed or queued */
3196                 memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3197                 
3198                 return;
3199         }
3200         if (e_state != EPOINT_STATE_IDLE)
3201         {
3202                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3203                 return;
3204         }
3205         /* if an internal extension is dialed, copy that number */
3206         if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3207                 SCPY(e_ext.number, param->setup.dialinginfo.id);
3208         /* if an internal extension is dialed, get extension's info about caller */
3209         if (e_ext.number[0]) 
3210         {
3211                 if (!read_extension(&e_ext, e_ext.number))
3212                 {
3213                         e_ext.number[0] = '\0';
3214                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3215                 }
3216         }
3217
3218         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3219         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3220         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3221         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3222
3223         /* process (voice over) data calls */
3224         if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO)
3225         {
3226                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3227                 memset(&e_capainfo, 0, sizeof(e_capainfo));
3228                 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3229                 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3230                 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3231         }
3232
3233         new_state(EPOINT_STATE_OUT_SETUP);
3234         /* call special setup routine */
3235         out_setup();
3236 }
3237
3238 /* join MESSAGE_mISDNSIGNAL */
3239 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3240 {
3241         struct message *message;
3242
3243         while(portlist)
3244         {
3245                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3246                 memcpy(&message->param, param, sizeof(union parameter));
3247                 message_put(message);
3248                 portlist = portlist->next;
3249         }
3250 }
3251
3252 /* join MESSAGE_NOTIFY */
3253 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3254 {
3255         struct message *message;
3256         int new_state;
3257
3258         if (param->notifyinfo.notify)
3259         {
3260                 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3261 //              /* if notification was generated locally, we turn hold music on/off */ 
3262 //              if (param->notifyinfo.local)
3263 // 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)
3264                 {
3265                         if (e_hold)
3266                         {
3267                                 /* unhold if */
3268                                 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND)
3269                                 {
3270                                         if (!strcmp(e_tone, "hold")) // don't interrupt other tones
3271                                         {
3272                                                 while(portlist)
3273                                                 {
3274                                                         set_tone(portlist, "");
3275                                                         portlist = portlist->next;
3276                                                 }
3277                                         }
3278                                         portlist = ea_endpoint->ep_portlist;
3279                                         e_hold = 0;
3280                                 }
3281                         } else {
3282                                 /* hold if */
3283                                 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND)
3284                                 {
3285                                         while(portlist)
3286                                         {
3287                                                 set_tone(portlist, "hold");
3288                                                 portlist = portlist->next;
3289                                         }
3290                                         portlist = ea_endpoint->ep_portlist;
3291                                         e_hold = 1;
3292                                 }
3293                         }
3294                 }
3295                 /* save new state */
3296                 e_tx_state = new_state;
3297         }
3298
3299         /* notify port(s) about it */
3300         while(portlist)
3301         {
3302                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3303                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
3304                 /* handle restricted caller ids */
3305                 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3306                 /* display callerid if desired for extension */
3307                 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));
3308                 message_put(message);
3309                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3310                 portlist = portlist->next;
3311         }
3312 }
3313
3314 /* JOIN sends messages to the endpoint
3315  */
3316 void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, union parameter *param)
3317 {
3318         struct port_list *portlist;
3319         struct message *message;
3320
3321         if (!join_id)
3322         {
3323                 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3324                 return;
3325         }
3326
3327         portlist = ea_endpoint->ep_portlist;
3328
3329         /* send MESSAGE_DATA to port */
3330         if (message_type == MESSAGE_DATA)
3331         {
3332                 if (join_id == ea_endpoint->ep_join_id) // still linked with JOIN
3333                 {
3334                         /* skip if no port relation */
3335                         if (!portlist)
3336                                 return;
3337                         /* skip if more than one port relation */
3338                         if (portlist->next)
3339                                 return;
3340                         /* forward audio data to port */
3341                         message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3342                         return;
3343                 }
3344         }
3345
3346 //      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);
3347         switch(message_type)
3348         {
3349                 /* JOIN SENDS TONE message */
3350                 case MESSAGE_TONE:
3351                 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);
3352                 set_tone(portlist, param->tone.name);
3353                 break;
3354
3355                 /* JOIN SENDS CRYPT message */
3356                 case MESSAGE_CRYPT:
3357                 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);
3358                 join_crypt(portlist, message_type, param);
3359                 break;
3360
3361                 /* JOIN sends INFORMATION message */
3362                 case MESSAGE_INFORMATION:
3363                 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);
3364                 join_information(portlist, message_type, param);
3365                 break;
3366
3367                 /* JOIN sends FACILITY message */
3368                 case MESSAGE_FACILITY:
3369                 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);
3370                 join_facility(portlist, message_type, param);
3371                 break;
3372
3373                 /* JOIN sends OVERLAP message */
3374                 case MESSAGE_OVERLAP:
3375                 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);
3376                 if (e_state!=EPOINT_STATE_IN_SETUP
3377                  && e_state!=EPOINT_STATE_IN_OVERLAP)
3378                 {
3379                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3380                         break;
3381                 }
3382                 join_overlap(portlist, message_type, param);
3383                 break;
3384
3385                 /* JOIN sends PROCEEDING message */
3386                 case MESSAGE_PROCEEDING:
3387                 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);
3388                 if(e_state!=EPOINT_STATE_IN_OVERLAP)
3389                 {
3390                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3391                         break;
3392                 }
3393                 join_proceeding(portlist, message_type, param);
3394                 break;
3395
3396                 /* JOIN sends ALERTING message */
3397                 case MESSAGE_ALERTING:
3398                 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);
3399                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3400                  && e_state!=EPOINT_STATE_IN_PROCEEDING)
3401                 {
3402                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3403                         break;
3404                 }
3405                 join_alerting(portlist, message_type, param);
3406                 break;
3407
3408                 /* JOIN sends CONNECT message */
3409                 case MESSAGE_CONNECT:
3410                 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);
3411                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3412                  && e_state!=EPOINT_STATE_IN_PROCEEDING
3413                  && e_state!=EPOINT_STATE_IN_ALERTING)
3414                 {
3415                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3416                         break;
3417                 }
3418                 join_connect(portlist, message_type, param);
3419                 break;
3420
3421                 /* JOIN sends DISCONNECT/RELEASE message */
3422                 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3423                 case MESSAGE_RELEASE: /* JOIN releases */
3424                 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);
3425                 join_disconnect_release(message_type, param);
3426                 break;
3427
3428                 /* JOIN sends SETUP message */
3429                 case MESSAGE_SETUP:
3430                 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);
3431                 join_setup(portlist, message_type, param);
3432                 break;
3433
3434                 /* JOIN sends special mISDNSIGNAL message */
3435                 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3436                 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);
3437                 join_mISDNsignal(portlist, message_type, param);
3438                 break;
3439
3440 #if 0
3441                 /* JOIN requests bchannel */
3442                 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3443                 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);
3444                 /* only one port is expected to be connected to bchannel */
3445                 if (!portlist)
3446                         break;
3447                 if (portlist->next)
3448                         break;
3449                 e_join_pattern = 1;
3450                 SCPY(e_tone, "");
3451                 set_tone(portlist, NULL);
3452                 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3453                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3454                 break;
3455 #endif
3456
3457                 /* JOIN has pattern available */
3458                 case MESSAGE_PATTERN: /* indicating pattern available */
3459                 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);
3460                 if (!e_join_pattern)
3461                 {
3462                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3463                         e_join_pattern = 1;
3464                         SCPY(e_tone, "");
3465                         while(portlist)
3466                         {
3467                                 set_tone(portlist, NULL);
3468                                 portlist = portlist->next;
3469                         }
3470                         /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3471                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3472                         message->param.audiopath = CHANNEL_STATE_CONNECT;
3473                         message_put(message);
3474 //                      /* tell remote epoint to connect audio also, because we like to hear the patterns */
3475 //                      message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_REMOTE_AUDIO);
3476 //                      message->param.audiopath = CHANNEL_STATE_CONNECT;
3477 //                      message_put(message);
3478 // patterns are available, remote already connected audio
3479                 }
3480                 break;
3481
3482                 /* JOIN has no pattern available */
3483                 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3484                 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);
3485                 if (e_join_pattern)
3486                 {
3487                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3488                         e_join_pattern = 0;
3489                         /* disconnect our audio tx and rx */
3490                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3491                         message->param.audiopath = CHANNEL_STATE_HOLD;
3492                         message_put(message);
3493                 }
3494                 break;
3495
3496 #if 0
3497                 /* JOIN (dunno at the moment) */
3498                 case MESSAGE_REMOTE_AUDIO:
3499                 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);
3500                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3501                 message->param.audiopath = param->channel;
3502                 message_put(message);
3503                 break;
3504 #endif
3505
3506                 /* JOIN sends a notify message */
3507                 case MESSAGE_NOTIFY:
3508                 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);
3509                 join_notify(portlist, message_type, param);
3510                 break;
3511
3512                 default:
3513                 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);
3514         }
3515 }
3516
3517
3518 /* pick_join will connect the first incoming call found. the endpoint
3519  * will receivce a MESSAGE_CONNECT.
3520  */
3521 int match_list(char *list, char *item)
3522 {
3523         char *end, *next = NULL;
3524
3525         /* no list make matching */
3526         if (!list)
3527                 return(1);
3528
3529         while(42)
3530         {
3531                 /* eliminate white spaces */
3532                 while (*list <= ' ')
3533                         list++;
3534                 if (*list == ',')
3535                 {
3536                         list++;
3537                         continue;
3538                 }
3539                 /* if end of list is reached, we return */
3540                 if (list[0] == '\0')
3541                         return(0);
3542                 /* if we have more than one entry (left) */
3543                 if ((end = strchr(list, ',')))
3544                         next = end + 1;
3545                 else
3546                         next = end = strchr(list, '\0');
3547                 while (*(end-1) <= ' ')
3548                         end--;
3549                 /* if string part matches item */
3550                 if (!strncmp(list, item, end-list))
3551                         return(1);
3552                 list = next;
3553         }
3554 }
3555
3556 void EndpointAppPBX::pick_join(char *extensions)
3557 {
3558         struct message *message;
3559         struct port_list *portlist;
3560         class Port *port;
3561         class EndpointAppPBX *eapp, *found;
3562         class Join *join;
3563         class JoinPBX *joinpbx;
3564         struct join_relation *relation;
3565         int vbox;
3566
3567         /* find an endpoint that is ringing internally or vbox with higher priority */
3568         vbox = 0;
3569         found = NULL;
3570         eapp = apppbx_first;
3571         while(eapp)
3572         {
3573                 if (eapp!=this && ea_endpoint->ep_portlist)
3574                 {
3575                         portlist = eapp->ea_endpoint->ep_portlist;
3576                         while(portlist)
3577                         {
3578                                 if ((port = find_port_id(portlist->port_id)))
3579                                 {
3580                                         if (port->p_type == PORT_TYPE_VBOX_OUT)
3581                                         {
3582                                                 if (match_list(extensions, eapp->e_ext.number))
3583                                                 {
3584                                                         found = eapp;
3585                                                         vbox = 1;
3586                                                         break;
3587                                                 }
3588                                         }
3589                                         if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT)
3590                                          && port->p_state==PORT_STATE_OUT_ALERTING)
3591                                                 if (match_list(extensions, eapp->e_ext.number))
3592                                                 {
3593                                                         found = eapp;
3594                                                 }
3595                                 }
3596                                 portlist = portlist->next;
3597                         }
3598                         if (portlist)
3599                                 break;
3600                 }
3601                 eapp = eapp->next;
3602         }
3603
3604         /* if no endpoint found */
3605         if (!found)
3606         {
3607                 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);
3608 reject:
3609                 set_tone(ea_endpoint->ep_portlist, "cause_10");
3610                 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3611                 new_state(EPOINT_STATE_OUT_DISCONNECT);
3612                 return;
3613         }
3614         eapp = found;
3615
3616         if (ea_endpoint->ep_join_id)
3617         {
3618                 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3619                 goto reject;
3620         }
3621         if (!eapp->ea_endpoint->ep_join_id)
3622         {
3623                 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3624                 goto reject;
3625         }
3626         join = find_join_id(eapp->ea_endpoint->ep_join_id);
3627         if (!join)
3628         {
3629                 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3630                 goto reject;
3631         }
3632         if (join->j_type != JOIN_TYPE_PBX)
3633         {
3634                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3635                 goto reject;
3636         }
3637         joinpbx = (class JoinPBX *)join;
3638         relation = joinpbx->j_relation;
3639         if (!relation)
3640         {
3641                 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3642                 goto reject;
3643         }
3644         while (relation->epoint_id != eapp->ea_endpoint->ep_serial)
3645         {
3646                 relation = relation->next;
3647                 if (!relation)
3648                 {
3649                         PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3650                         goto reject;
3651                 }
3652         }
3653
3654         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3655
3656         if (options.deb & DEBUG_EPOINT)
3657         {
3658                 class Join *debug_c = join_first;
3659                 class Endpoint *debug_e = epoint_first;
3660                 class Port *debug_p = port_first;
3661
3662                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3663
3664                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3665                 while(debug_c)
3666                 {
3667                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3668                         debug_c = debug_c->next;
3669                 }
3670                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3671                 while(debug_e)
3672                 {
3673                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3674                         debug_e = debug_e->next;
3675                 }
3676                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3677                 while(debug_p)
3678                 {
3679                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3680                         debug_p = debug_p->next;
3681                 }
3682         }
3683
3684         /* relink join */
3685         ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3686         relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3687         eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3688
3689         /* connnecting our endpoint */
3690         new_state(EPOINT_STATE_CONNECT);
3691         e_dtmf = 1;
3692         set_tone(ea_endpoint->ep_portlist, NULL);
3693
3694         /* now we send a release to the ringing endpoint */
3695         message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3696         message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3697         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3698         message_put(message);
3699
3700         /* we send a connect to the join with our caller id */
3701         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3702         SCPY(message->param.connectinfo.id, e_callerinfo.id);
3703         message->param.connectinfo.present = e_callerinfo.present;
3704         message->param.connectinfo.screen = e_callerinfo.screen;
3705         message->param.connectinfo.itype = e_callerinfo.itype;
3706         message->param.connectinfo.ntype = e_callerinfo.ntype;
3707         message_put(message);
3708
3709         /* we send a connect to our port with the remote callerid */
3710         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3711         SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3712         message->param.connectinfo.present = eapp->e_callerinfo.present;
3713         message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3714         message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3715         message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3716         /* handle restricted caller ids */
3717         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);
3718         /* display callerid if desired for extension */
3719         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));
3720         message_put(message);
3721
3722         /* we send a connect to the audio path (not for vbox) */
3723         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3724         message->param.audiopath = CHANNEL_STATE_CONNECT;
3725         message_put(message);
3726
3727         /* beeing paranoid, we make call update */
3728         joinpbx->j_updatebridge = 1;
3729
3730         if (options.deb & DEBUG_EPOINT)
3731         {
3732                 class Join *debug_c = join_first;
3733                 class Endpoint *debug_e = epoint_first;
3734                 class Port *debug_p = port_first;
3735
3736                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3737
3738                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3739                 while(debug_c)
3740                 {
3741                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3742                         debug_c = debug_c->next;
3743                 }
3744                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3745                 while(debug_e)
3746                 {
3747                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3748                         debug_e = debug_e->next;
3749                 }
3750                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3751                 while(debug_p)
3752                 {
3753                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3754                         debug_p = debug_p->next;
3755                 }
3756         }
3757 }
3758
3759
3760 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3761  */
3762 void EndpointAppPBX::join_join(void)
3763 {
3764         struct message *message;
3765         struct join_relation *our_relation, *other_relation;
3766         struct join_relation **our_relation_pointer, **other_relation_pointer;
3767         class Join *our_join, *other_join;
3768         class JoinPBX *our_joinpbx, *other_joinpbx;
3769         class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3770         class Port *our_port, *other_port;
3771         class Pdss1 *our_pdss1, *other_pdss1;
3772
3773         /* are we a candidate to join a join */
3774         our_join = find_join_id(ea_endpoint->ep_join_id);
3775         if (!our_join)
3776         {
3777                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3778                 return;
3779         }
3780         if (our_join->j_type != JOIN_TYPE_PBX)
3781         {
3782                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3783                 return;
3784         }
3785         our_joinpbx = (class JoinPBX *)our_join;
3786         if (!ea_endpoint->ep_portlist)
3787         {
3788                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3789                 return;
3790         }
3791         if (!e_ext.number[0])
3792         {
3793                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3794                 return;
3795         }
3796         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3797         if (!our_port)
3798         {
3799                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3800                 return;
3801         }
3802         if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
3803         {
3804                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3805                 return;
3806         }
3807         our_pdss1 = (class Pdss1 *)our_port;
3808
3809         /* find an endpoint that is on hold and has the same mISDNport that we are on */
3810         other_eapp = apppbx_first;
3811         while(other_eapp)
3812         {
3813                 if (other_eapp == this)
3814                 {
3815                         other_eapp = other_eapp->next;
3816                         continue;
3817                 }
3818                 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);
3819                 if (other_eapp->e_ext.number[0] /* has terminal */
3820                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3821                  && other_eapp->ea_endpoint->ep_join_id) /* has join */
3822                 {
3823                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3824                         if (other_port) /* port still exists */
3825                         {
3826                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3827                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) /* port is isdn nt-mode */
3828                                 {
3829                                         other_pdss1 = (class Pdss1 *)other_port;
3830                                         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);
3831                                         if (other_pdss1->p_m_hold /* port is on hold */
3832                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3833                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3834                                                 break;
3835                                 } else
3836                                 {
3837                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3838                                 }
3839                         } else
3840                         {
3841                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3842                         }
3843                 }
3844                 other_eapp = other_eapp->next;
3845         }
3846         if (!other_eapp)
3847         {
3848                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn interface with port on hold.\n", ea_endpoint->ep_serial);
3849                 return;
3850         }
3851         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port on hold found.\n", ea_endpoint->ep_serial);
3852
3853         /* if we have the same join */
3854         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id)
3855         {
3856                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we an the other have the same join.\n", ea_endpoint->ep_serial);
3857                 return;
3858         }
3859         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3860         if (!other_join)
3861         {
3862                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3863                 return;
3864         }
3865         if (other_join->j_type != JOIN_TYPE_PBX)
3866         {
3867                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3868                 return;
3869         }
3870         other_joinpbx = (class JoinPBX *)other_join;
3871         if (our_joinpbx->j_partyline && other_joinpbx->j_partyline)
3872         {
3873                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3874                 return;
3875         }
3876
3877         /* remove relation to endpoint for join on hold */
3878         other_relation = other_joinpbx->j_relation;
3879         other_relation_pointer = &other_joinpbx->j_relation;
3880         while(other_relation)
3881         {
3882                 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial)
3883                 {
3884                 /* detach other endpoint on hold */
3885                         *other_relation_pointer = other_relation->next;
3886                         FREE(other_relation, sizeof(struct join_relation));
3887                         cmemuse--;
3888                         other_relation = *other_relation_pointer;
3889                         other_eapp->ea_endpoint->ep_join_id = NULL;
3890                         continue;
3891                 }
3892
3893                 /* change join/hold pointer of endpoint to the new join */
3894                 temp_epoint = find_epoint_id(other_relation->epoint_id);
3895                 if (temp_epoint)
3896                 {
3897                         if (temp_epoint->ep_join_id == other_join->j_serial)
3898                                 temp_epoint->ep_join_id = our_join->j_serial;
3899                 }
3900
3901                 other_relation_pointer = &other_relation->next;
3902                 other_relation = other_relation->next;
3903         }
3904         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3905
3906         /* join call relations */
3907         our_relation = our_joinpbx->j_relation;
3908         our_relation_pointer = &our_joinpbx->j_relation;
3909         while(our_relation)
3910         {
3911                 our_relation_pointer = &our_relation->next;
3912                 our_relation = our_relation->next;
3913         }
3914         *our_relation_pointer = other_joinpbx->j_relation;
3915         other_joinpbx->j_relation = NULL;
3916         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3917
3918         /* release endpoint on hold */
3919         message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3920         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3921         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3922         message_put(message);
3923         
3924         /* if we are not a partyline, we get partyline state from other join */
3925         our_joinpbx->j_partyline += other_joinpbx->j_partyline; 
3926
3927         /* remove empty join */
3928         delete other_join;
3929         PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3930
3931         /* mixer must update */
3932         our_joinpbx->j_updatebridge = 1; /* update mixer flag */
3933
3934         /* we send a retrieve to that endpoint */
3935         // mixer will update the hold-state of the join and send it to the endpoints is changes
3936 }
3937
3938
3939 /* check if we have an external call
3940  * this is used to check for encryption ability
3941  */
3942 int EndpointAppPBX::check_external(char **errstr, class Port **port)
3943 {
3944         struct join_relation *relation;
3945         class Join *join;
3946         class JoinPBX *joinpbx;
3947         class Endpoint *epoint;
3948
3949         /* some paranoia check */
3950         if (!ea_endpoint->ep_portlist)
3951         {
3952                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3953                 *errstr = "No Call";
3954                 return(1);
3955         }
3956         if (!e_ext.number[0])
3957         {
3958                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3959                 *errstr = "No Call";
3960                 return(1);
3961         }
3962
3963         /* check if we have a join with 2 parties */
3964         join = find_join_id(ea_endpoint->ep_join_id);
3965         if (!join)
3966         {
3967                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3968                 *errstr = "No Call";
3969                 return(1);
3970         }
3971         if (join->j_type != JOIN_TYPE_PBX)
3972         {
3973                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3974                 *errstr = "No PBX Call";
3975                 return(1);
3976         }
3977         joinpbx = (class JoinPBX *)join;
3978         relation = joinpbx->j_relation;
3979         if (!relation)
3980         {
3981                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3982                 *errstr = "No Call";
3983                 return(1);
3984         }
3985         if (!relation->next)
3986         {
3987                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3988                 *errstr = "No Call";
3989                 return(1);
3990         }
3991         if (relation->next->next)
3992         {
3993                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3994                 *errstr = "Err: Conference";
3995                 return(1);
3996         }
3997         if (relation->epoint_id == ea_endpoint->ep_serial)
3998         {
3999                 relation = relation->next;
4000                 if (relation->epoint_id == ea_endpoint->ep_serial)
4001                 {
4002                         PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4003                         *errstr = "Software Error";
4004                         return(1);
4005                 }
4006         }
4007
4008         /* check remote port for external call */
4009         epoint = find_epoint_id(relation->epoint_id);
4010         if (!epoint)
4011         {
4012                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4013                 *errstr = "No Call";
4014                 return(1);
4015         }
4016         if (!epoint->ep_portlist)
4017         {
4018                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4019                 *errstr = "No Call";
4020                 return(1);
4021         }
4022         *port = find_port_id(epoint->ep_portlist->port_id);
4023         if (!(*port))
4024         {
4025                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4026                 *errstr = "No Call";
4027                 return(1);
4028         }
4029         if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) /* port is not external isdn */
4030         {
4031                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4032                 *errstr = "No Ext Call";
4033                 return(1);
4034         }
4035         if ((*port)->p_state != PORT_STATE_CONNECT)
4036         {
4037                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4038                 *errstr = "No Ext Connect";
4039                 return(1);
4040         }
4041         return(0);
4042 }
4043
4044 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned long port_id, int dir)
4045 {
4046         char *logtext = "unknown";
4047         char buffer[64];
4048
4049         switch(message_type)
4050         {
4051                 case MESSAGE_SETUP:
4052                 trace_header("SETUP", dir);
4053                 if (dir == DIRECTION_OUT)
4054                         add_trace("to", NULL, "CH(%lu)", port_id);
4055                 if (dir == DIRECTION_IN)
4056                         add_trace("from", NULL, "CH(%lu)", port_id);
4057                 if (param->setup.callerinfo.extension[0])
4058                         add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4059                 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype));
4060                 switch(param->setup.callerinfo.present)
4061                 {
4062                         case INFO_PRESENT_RESTRICTED:
4063                         add_trace("caller id", "present", "restricted");
4064                         break;
4065                         case INFO_PRESENT_ALLOWED:
4066                         add_trace("caller id", "present", "allowed");
4067                         break;
4068                         default:
4069                         add_trace("caller id", "present", "not available");
4070                 }
4071                 if (param->setup.redirinfo.id[0])
4072                 {
4073                         add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype));
4074                         switch(param->setup.redirinfo.present)
4075                         {
4076                                 case INFO_PRESENT_RESTRICTED:
4077                                 add_trace("redir'ing", "present", "restricted");
4078                                 break;
4079                                 case INFO_PRESENT_ALLOWED:
4080                                 add_trace("redir'ing", "present", "allowed");
4081                                 break;
4082                                 default:
4083                                 add_trace("redir'ing", "present", "not available");
4084                         }
4085                 }
4086                 if (param->setup.dialinginfo.id[0])
4087                         add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4088                 end_trace();
4089                 break;
4090
4091                 case MESSAGE_OVERLAP:
4092                 trace_header("SETUP ACKNOWLEDGE", dir);
4093                 if (dir == DIRECTION_OUT)
4094                         add_trace("to", NULL, "CH(%lu)", port_id);
4095                 if (dir == DIRECTION_IN)
4096                         add_trace("from", NULL, "CH(%lu)", port_id);
4097                 end_trace();
4098                 break;
4099
4100                 case MESSAGE_PROCEEDING:
4101                 trace_header("PROCEEDING", dir);
4102                 if (dir == DIRECTION_OUT)
4103                         add_trace("to", NULL, "CH(%lu)", port_id);
4104                 if (dir == DIRECTION_IN)
4105                         add_trace("from", NULL, "CH(%lu)", port_id);
4106                 end_trace();
4107                 break;
4108
4109                 case MESSAGE_ALERTING:
4110                 trace_header("ALERTING", dir);
4111                 if (dir == DIRECTION_OUT)
4112                         add_trace("to", NULL, "CH(%lu)", port_id);
4113                 if (dir == DIRECTION_IN)
4114                         add_trace("from", NULL, "CH(%lu)", port_id);
4115                 end_trace();
4116                 break;
4117
4118                 case MESSAGE_CONNECT:
4119                 trace_header("CONNECT", dir);
4120                 if (dir == DIRECTION_OUT)
4121                         add_trace("to", NULL, "CH(%lu)", port_id);
4122                 if (dir == DIRECTION_IN)
4123                         add_trace("from", NULL, "CH(%lu)", port_id);
4124                 if (param->connectinfo.extension[0])
4125                         add_trace("extension", NULL, "%s", param->connectinfo.extension);
4126                 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype));
4127                 switch(param->connectinfo.present)
4128                 {
4129                         case INFO_PRESENT_RESTRICTED:
4130                         add_trace("connect id", "present", "restricted");
4131                         break;
4132                         case INFO_PRESENT_ALLOWED:
4133                         add_trace("connect id", "present", "allowed");
4134                         break;
4135                         default:
4136                         add_trace("connect id", "present", "not available");
4137                 }
4138                 end_trace();
4139                 break;
4140
4141                 case MESSAGE_DISCONNECT:
4142                 case MESSAGE_RELEASE:
4143                 if (message_type == MESSAGE_DISCONNECT)
4144                         trace_header("DISCONNECT", dir);
4145                 else
4146                         trace_header("RELEASE", dir);
4147                 if (dir == DIRECTION_OUT)
4148                         add_trace("to", NULL, "CH(%lu)", port_id);
4149                 if (dir == DIRECTION_IN)
4150                         add_trace("from", NULL, "CH(%lu)", port_id);
4151                 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4152                 switch(param->disconnectinfo.location)
4153                 {
4154                         case LOCATION_USER:
4155                         add_trace("cause", "location", "0-User");
4156                         break;
4157                         case LOCATION_PRIVATE_LOCAL:
4158                         add_trace("cause", "location", "1-Local-PBX");
4159                         break;
4160                         case LOCATION_PUBLIC_LOCAL:
4161                         add_trace("cause", "location", "2-Local-Exchange");
4162                         break;
4163                         case LOCATION_TRANSIT:
4164                         add_trace("cause", "location", "3-Transit");
4165                         break;
4166                         case LOCATION_PUBLIC_REMOTE:
4167                         add_trace("cause", "location", "4-Remote-Exchange");
4168                         break;
4169                         case LOCATION_PRIVATE_REMOTE:
4170                         add_trace("cause", "location", "5-Remote-PBX");
4171                         break;
4172                         case LOCATION_INTERNATIONAL:
4173                         add_trace("cause", "location", "7-International-Exchange");
4174                         break;
4175                         case LOCATION_BEYOND:
4176                         add_trace("cause", "location", "10-Beyond-Interworking");
4177                         break;
4178                         default:
4179                         add_trace("cause", "location", "%d", param->disconnectinfo.location);
4180                 }
4181                 end_trace();
4182                 break;
4183
4184                 case MESSAGE_NOTIFY:
4185                 switch(param->notifyinfo.notify)
4186                 {
4187                         case 0x00:
4188                         logtext = "NULL";
4189                         break;
4190                         case 0x80:
4191                         logtext = "USER_SUSPENDED";
4192                         break;
4193                         case 0x82:
4194                         logtext = "BEARER_SERVICE_CHANGED";
4195                         break;
4196                         case 0x81:
4197                         logtext = "USER_RESUMED";
4198                         break;
4199                         case 0xc2:
4200                         logtext = "CONFERENCE_ESTABLISHED";
4201                         break;
4202                         case 0xc3:
4203                         logtext = "CONFERENCE_DISCONNECTED";
4204                         break;
4205                         case 0xc4:
4206                         logtext = "OTHER_PARTY_ADDED";
4207                         break;
4208                         case 0xc5:
4209                         logtext = "ISOLATED";
4210                         break;
4211                         case 0xc6:
4212                         logtext = "REATTACHED";
4213                         break;
4214                         case 0xc7:
4215                         logtext = "OTHER_PARTY_ISOLATED";
4216                         break;
4217                         case 0xc8:
4218                         logtext = "OTHER_PARTY_REATTACHED";
4219                         break;
4220                         case 0xc9:
4221                         logtext = "OTHER_PARTY_SPLIT";
4222                         break;
4223                         case 0xca:
4224                         logtext = "OTHER_PARTY_DISCONNECTED";
4225                         break;
4226                         case 0xcb:
4227                         logtext = "CONFERENCE_FLOATING";
4228                         break;
4229                         case 0xcc:
4230                         logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4231                         break;
4232                         case 0xcf:
4233                         logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4234                         break;
4235                         case 0xe0:
4236                         logtext = "CALL_IS_A_WAITING_CALL";
4237                         break;
4238                         case 0xe8:
4239                         logtext = "DIVERSION_ACTIVATED";
4240                         break;
4241                         case 0xe9:
4242                         logtext = "RESERVED_CT_1";
4243                         break;
4244                         case 0xea:
4245                         logtext = "RESERVED_CT_2";
4246                         break;
4247                         case 0xee:
4248                         logtext = "REVERSE_CHARGING";
4249                         break;
4250                         case 0xf9:
4251                         logtext = "REMOTE_HOLD";
4252                         break;
4253                         case 0xfa:
4254                         logtext = "REMOTE_RETRIEVAL";
4255                         break;
4256                         case 0xfb:
4257                         logtext = "CALL_IS_DIVERTING";
4258                         break;
4259                         default:
4260                         SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4261                         logtext = buffer;
4262
4263                 }
4264                 trace_header("NOTIFY", dir);
4265                 if (dir == DIRECTION_OUT)
4266                         add_trace("to", NULL, "CH(%lu)", port_id);
4267                 if (dir == DIRECTION_IN)
4268                         add_trace("from", NULL, "CH(%lu)", port_id);
4269                 if (param->notifyinfo.notify)
4270                         add_trace("indicator", NULL, "%s", logtext);
4271                 if (param->notifyinfo.id[0])
4272                 {
4273                         add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype));
4274                         switch(param->notifyinfo.present)
4275                         {
4276                                 case INFO_PRESENT_RESTRICTED:
4277                                 add_trace("redir'on", "present", "restricted");
4278                                 break;
4279                                 case INFO_PRESENT_ALLOWED:
4280                                 add_trace("redir'on", "present", "allowed");
4281                                 break;
4282                                 default:
4283                                 add_trace("redir'on", "present", "not available");
4284                         }
4285                 }
4286                 if (param->notifyinfo.display[0])
4287                         add_trace("display", NULL, "%s", param->notifyinfo.display);
4288                 end_trace();
4289                 break;
4290
4291                 case MESSAGE_INFORMATION:
4292                 trace_header("INFORMATION", dir);
4293                 if (dir == DIRECTION_OUT)
4294                         add_trace("to", NULL, "CH(%lu)", port_id);
4295                 if (dir == DIRECTION_IN)
4296                         add_trace("from", NULL, "CH(%lu)", port_id);
4297                 add_trace("dialing", NULL, "%s", param->information.id);
4298                 end_trace();
4299                 break;
4300
4301                 case MESSAGE_FACILITY:
4302                 trace_header("FACILITY", dir);
4303                 if (dir == DIRECTION_OUT)
4304                         add_trace("to", NULL, "CH(%lu)", port_id);
4305                 if (dir == DIRECTION_IN)
4306                         add_trace("from", NULL, "CH(%lu)", port_id);
4307                 end_trace();
4308                 break;
4309
4310                 case MESSAGE_TONE:
4311                 trace_header("TONE", dir);
4312                 if (dir == DIRECTION_OUT)
4313                         add_trace("to", NULL, "CH(%lu)", port_id);
4314                 if (dir == DIRECTION_IN)
4315                         add_trace("from", NULL, "CH(%lu)", port_id);
4316                 if (param->tone.name[0])
4317                 {
4318                         add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4319                         add_trace("name", NULL, "%s", param->tone.name);
4320                 } else
4321                         add_trace("off", NULL, NULL);
4322                 end_trace();
4323                 break;
4324
4325                 case MESSAGE_SUSPEND:
4326                 case MESSAGE_RESUME:
4327                 if (message_type == MESSAGE_SUSPEND)
4328                         trace_header("SUSPEND", dir);
4329                 else
4330                         trace_header("RESUME", dir);
4331                 if (dir == DIRECTION_OUT)
4332                         add_trace("to", NULL, "CH(%lu)", port_id);
4333                 if (dir == DIRECTION_IN)
4334                         add_trace("from", NULL, "CH(%lu)", port_id);
4335                 if (param->parkinfo.len)
4336                         add_trace("length", NULL, "%d", param->parkinfo.len);
4337                 end_trace();
4338                 break;
4339
4340 #if 0
4341                 case MESSAGE_BCHANNEL:
4342                 trace_header("BCHANNEL", dir);
4343                 switch(param->bchannel.type)
4344                 {
4345                         case BCHANNEL_REQUEST:
4346                         add_trace("type", NULL, "request");
4347                         break;
4348                         case BCHANNEL_ASSIGN:
4349                         add_trace("type", NULL, "assign");
4350                         break;
4351                         case BCHANNEL_ASSIGN_ACK:
4352                         add_trace("type", NULL, "assign_ack");
4353                         break;
4354                         case BCHANNEL_REMOVE:
4355                         add_trace("type", NULL, "remove");
4356                         break;
4357                         case BCHANNEL_REMOVE_ACK:
4358                         add_trace("type", NULL, "remove_ack");
4359                         break;
4360                 }
4361                 if (param->bchannel.addr)
4362                         add_trace("address", NULL, "%x", param->bchannel.addr);
4363                 end_trace();
4364                 break;
4365 #endif
4366
4367                 default:
4368                 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4369         }
4370 }
4371
4372 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, char *display)
4373 {
4374         struct message *message;
4375
4376         if (!portlist)
4377                 return;
4378         if (!portlist->port_id)
4379                 return;
4380
4381         if (!e_connectedmode)
4382         {
4383                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4384                 message->param.disconnectinfo.cause = cause;
4385                 message->param.disconnectinfo.location = location;
4386                 if (display[0])
4387                         SCPY(message->param.disconnectinfo.display, display);
4388                 else
4389                         SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4390         } else
4391         {
4392                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4393                 if (display[0])
4394                         SCPY(message->param.notifyinfo.display, display);
4395                 else
4396                         SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4397         }
4398         message_put(message);
4399         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
4400 }
4401
4402