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