fixes & improvements
[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         if (message_type == MESSAGE_DISCONNECT)
2384         {
2385                 /* tone to disconnected end */
2386                 SPRINT(buffer, "cause_%02x", cause);
2387                 if (ea_endpoint->ep_portlist)
2388                         set_tone(ea_endpoint->ep_portlist, buffer);
2389
2390                 new_state(EPOINT_STATE_IN_DISCONNECT);
2391         }
2392
2393         if (ea_endpoint->ep_join_id)
2394         {
2395                 int haspatterns = 0;
2396                 /* check if pattern is available */
2397                 if (ea_endpoint->ep_portlist)
2398                 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2399                 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 
2400                  && message_type != MESSAGE_RELEASE) // if we release, we are done
2401                         haspatterns = 1;
2402                 if (haspatterns)
2403                 {
2404                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2405                         /* indicate patterns */
2406                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2407                         message_put(message);
2408                         /* connect audio, if not already */
2409                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
2410                         message->param.channel = CHANNEL_STATE_CONNECT;
2411                         message_put(message);
2412                         /* send disconnect */
2413                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2414                         memcpy(&message->param, param, sizeof(union parameter));
2415                         message_put(message);
2416                         /* disable encryption if disconnected */
2417 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2418                         if (e_crypt_state)
2419                                 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2420                         return;
2421                 } else
2422                 {
2423                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2424                 }
2425         }
2426         if (message_type == MESSAGE_RELEASE)
2427                 ea_endpoint->free_portlist(portlist);
2428         release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */
2429         return; /* must exit here */
2430 }
2431
2432 /* port MESSAGE_TIMEOUT */
2433 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2434 {
2435         char cause[16];
2436
2437         trace_header("TIMEOUT", DIRECTION_IN);
2438         message_type = MESSAGE_DISCONNECT;
2439         switch (param->state)
2440         {
2441                 case PORT_STATE_OUT_SETUP:
2442                 case PORT_STATE_OUT_OVERLAP:
2443                 add_trace("state", NULL, "outgoing setup/dialing");
2444                 end_trace();
2445                 /* no user responding */
2446                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2447                 return; /* must exit here */
2448
2449                 case PORT_STATE_IN_SETUP:
2450                 case PORT_STATE_IN_OVERLAP:
2451                 add_trace("state", NULL, "incoming setup/dialing");
2452                 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2453                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2454                 break;
2455
2456                 case PORT_STATE_OUT_PROCEEDING:
2457                 add_trace("state", NULL, "outgoing proceeding");
2458                 end_trace();
2459                 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2460                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2461                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2462                 return; /* must exit here */
2463
2464                 case PORT_STATE_IN_PROCEEDING:
2465                 add_trace("state", NULL, "incoming proceeding");
2466                 param->disconnectinfo.cause = CAUSE_NOUSER;
2467                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2468                 break;
2469
2470                 case PORT_STATE_OUT_ALERTING:
2471                 add_trace("state", NULL, "outgoing alerting");
2472                 end_trace();
2473                 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2474                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2475                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2476                 return; /* must exit here */
2477
2478                 case PORT_STATE_CONNECT:
2479                 add_trace("state", NULL, "connect");
2480                 end_trace();
2481                 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2482                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2483                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2484                 return; /* must exit here */
2485
2486                 case PORT_STATE_IN_ALERTING:
2487                 add_trace("state", NULL, "incoming alerting");
2488                 param->disconnectinfo.cause = CAUSE_NOANSWER;
2489                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2490                 break;
2491
2492                 case PORT_STATE_IN_DISCONNECT:
2493                 case PORT_STATE_OUT_DISCONNECT:
2494                 add_trace("state", NULL, "disconnect");
2495                 end_trace();
2496                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2497                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2498                 return; /* must exit here */
2499
2500                 default:
2501                 param->disconnectinfo.cause = 31; /* normal unspecified */
2502                 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2503         }
2504         end_trace();
2505         /* release call, disconnect isdn */
2506         e_join_pattern = 0;
2507         new_state(EPOINT_STATE_OUT_DISCONNECT);
2508         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2509         SCPY(e_tone, cause);
2510         while(portlist)
2511         {
2512                 set_tone(portlist, cause);
2513                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2514                 portlist = portlist->next;
2515         }
2516         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2517 }
2518
2519 /* port MESSAGE_NOTIFY */
2520 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2521 {
2522         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2523
2524         struct message *message;
2525         char *logtext = "";
2526         char buffer[64];
2527
2528         /* signal to call tool */
2529         admin_call_response(e_adminid, ADMIN_CALL_NOTIFY, numberrize_callerinfo(param->notifyinfo.id,param->notifyinfo.ntype), 0, 0, param->notifyinfo.notify);
2530         if (param->notifyinfo.notify)
2531         {
2532                 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2533         }
2534
2535         /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2536         if (param->notifyinfo.local) switch(param->notifyinfo.notify)
2537         {
2538                 case INFO_NOTIFY_REMOTE_HOLD:
2539                 case INFO_NOTIFY_USER_SUSPENDED:
2540                 /* tell call about it */
2541                 if (ea_endpoint->ep_join_id)
2542                 {
2543                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
2544                         message->param.channel = CHANNEL_STATE_HOLD;
2545                         message_put(message);
2546                 }
2547                 break;
2548
2549                 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2550                 case INFO_NOTIFY_USER_RESUMED:
2551                 /* set volume of rx and tx */
2552                 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2553                 if (e_ext.txvol!=256 || e_ext.rxvol!=256)
2554                 if (portlist)
2555                 {
2556                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2557                         message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2558                         message->param.mISDNsignal.rxvol = e_ext.txvol;
2559                         message->param.mISDNsignal.txvol = e_ext.rxvol;
2560                         message_put(message);
2561                 }
2562                 /* set current tone */
2563                 if (portlist)
2564                         set_tone(portlist, e_tone);
2565                 /* tell call about it */
2566                 if (ea_endpoint->ep_join_id)
2567                 {
2568                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
2569                         message->param.channel = CHANNEL_STATE_CONNECT;
2570                         message_put(message);
2571                 }
2572                 break;
2573         }
2574
2575         /* get name of notify */
2576         switch(param->notifyinfo.notify)
2577         {
2578                 case 0x00:
2579                 logtext = "NULL";
2580                 break;
2581                 case 0x80:
2582                 logtext = "USER_SUSPENDED";
2583                 break;
2584                 case 0x82:
2585                 logtext = "BEARER_SERVICE_CHANGED";
2586                 break;
2587                 case 0x81:
2588                 logtext = "USER_RESUMED";
2589                 break;
2590                 case 0xc2:
2591                 logtext = "CONFERENCE_ESTABLISHED";
2592                 break;
2593                 case 0xc3:
2594                 logtext = "CONFERENCE_DISCONNECTED";
2595                 break;
2596                 case 0xc4:
2597                 logtext = "OTHER_PARTY_ADDED";
2598                 break;
2599                 case 0xc5:
2600                 logtext = "ISOLATED";
2601                 break;
2602                 case 0xc6:
2603                 logtext = "REATTACHED";
2604                 break;
2605                 case 0xc7:
2606                 logtext = "OTHER_PARTY_ISOLATED";
2607                 break;
2608                 case 0xc8:
2609                 logtext = "OTHER_PARTY_REATTACHED";
2610                 break;
2611                 case 0xc9:
2612                 logtext = "OTHER_PARTY_SPLIT";
2613                 break;
2614                 case 0xca:
2615                 logtext = "OTHER_PARTY_DISCONNECTED";
2616                 break;
2617                 case 0xcb:
2618                 logtext = "CONFERENCE_FLOATING";
2619                 break;
2620                 case 0xcc:
2621                 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2622                 break;
2623                 case 0xcf:
2624                 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2625                 break;
2626                 case 0xe0:
2627                 logtext = "CALL_IS_A_WAITING_CALL";
2628                 break;
2629                 case 0xe8:
2630                 logtext = "DIVERSION_ACTIVATED";
2631                 break;
2632                 case 0xe9:
2633                 logtext = "RESERVED_CT_1";
2634                 break;
2635                 case 0xea:
2636                 logtext = "RESERVED_CT_2";
2637                 break;
2638                 case 0xee:
2639                 logtext = "REVERSE_CHARGING";
2640                 break;
2641                 case 0xf9:
2642                 logtext = "REMOTE_HOLD";
2643                 break;
2644                 case 0xfa:
2645                 logtext = "REMOTE_RETRIEVAL";
2646                 break;
2647                 case 0xfb:
2648                 logtext = "CALL_IS_DIVERTING";
2649                 break;
2650                 default:
2651                 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2652                 logtext = buffer;
2653
2654         }
2655
2656         /* notify call if available */
2657         if (ea_endpoint->ep_join_id)
2658         {
2659                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2660                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
2661                 message_put(message);
2662         }
2663
2664 }
2665
2666 /* port MESSAGE_FACILITY */
2667 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2668 {
2669         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2670
2671         struct message *message;
2672
2673         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2674         memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2675         message_put(message);
2676 }
2677
2678 /* port MESSAGE_SUSPEND */
2679 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2680 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2681 {
2682         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2683
2684         /* epoint is now parked */
2685         ea_endpoint->ep_park = 1;
2686         memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2687         ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2688
2689         /* remove port relation */
2690         ea_endpoint->free_portlist(portlist);
2691 }
2692
2693 /* port MESSAGE_RESUME */
2694 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2695 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2696 {
2697         logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2698
2699         /* epoint is now resumed */
2700         ea_endpoint->ep_park = 0;
2701
2702 }
2703
2704
2705 /* port sends message to the endpoint
2706  */
2707 void EndpointAppPBX::ea_message_port(unsigned long port_id, int message_type, union parameter *param)
2708 {
2709         struct port_list *portlist;
2710         struct message *message;
2711
2712         portlist = ea_endpoint->ep_portlist;
2713         while(portlist)
2714         {
2715                 if (port_id == portlist->port_id)
2716                         break;
2717                 portlist = portlist->next;
2718         }
2719         if (!portlist)
2720         {
2721                 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);
2722                 return;
2723         }
2724
2725 //      PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2726         switch(message_type)
2727         {
2728                 case MESSAGE_DATA: /* data from port */
2729                 /* check if there is a call */
2730                 if (!ea_endpoint->ep_join_id)
2731                         break;
2732                 /* continue if only one portlist */
2733                 if (ea_endpoint->ep_portlist->next != NULL)
2734                         break;
2735                 /* forward message */
2736                 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);  
2737                 break;
2738
2739                 case MESSAGE_TONE_EOF: /* tone is end of file */
2740                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2741                 if (e_action)
2742                 {
2743                         if (e_action->index == ACTION_VBOX_PLAY)
2744                         {
2745                                 vbox_message_eof();
2746                         }
2747                         if (e_action->index == ACTION_EFI)
2748                         {
2749                                 efi_message_eof();
2750                         }
2751                 }
2752                 break;
2753
2754                 case MESSAGE_TONE_COUNTER: /* counter info received */
2755                 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);
2756                 if (e_action)
2757                 if (e_action->index == ACTION_VBOX_PLAY)
2758                 {
2759                         e_vbox_counter = param->counter.current;
2760                         if (param->counter.max >= 0)
2761                                 e_vbox_counter_max = param->counter.max;
2762                 }
2763                 break;
2764
2765                 /* PORT sends SETUP message */
2766                 case MESSAGE_SETUP:
2767                 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);
2768                 if (e_state!=EPOINT_STATE_IDLE)
2769                 {
2770                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2771                         break;
2772                 }
2773                 port_setup(portlist, message_type, param);
2774                 break;
2775
2776                 /* PORT sends INFORMATION message */
2777                 case MESSAGE_INFORMATION: /* additional digits received */
2778                 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);
2779                 port_information(portlist, message_type, param);
2780                 break;
2781
2782                 /* PORT sends FACILITY message */
2783                 case MESSAGE_FACILITY:
2784                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2785                 port_facility(portlist, message_type, param);
2786                 break;
2787
2788                 /* PORT sends DTMF message */
2789                 case MESSAGE_DTMF: /* dtmf digits received */
2790                 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);
2791                 port_dtmf(portlist, message_type, param);
2792                 break;
2793
2794                 /* PORT sends CRYPT message */
2795                 case MESSAGE_CRYPT: /* crypt response received */
2796                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2797                 port_crypt(portlist, message_type, param);
2798                 break;
2799
2800                 /* PORT sends MORE message */
2801                 case MESSAGE_OVERLAP:
2802                 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);
2803                 if (e_state != EPOINT_STATE_OUT_SETUP)
2804                 {
2805                         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);
2806                         break;
2807                 }
2808                 port_overlap(portlist, message_type, param);
2809                 break;
2810
2811                 /* PORT sends PROCEEDING message */
2812                 case MESSAGE_PROCEEDING: /* port is proceeding */
2813                 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);
2814                 if (e_state!=EPOINT_STATE_OUT_SETUP
2815                  && e_state!=EPOINT_STATE_OUT_OVERLAP)
2816                 {
2817                         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);
2818                         break;
2819                 }
2820                 port_proceeding(portlist, message_type, param);
2821                 break;
2822
2823                 /* PORT sends ALERTING message */
2824                 case MESSAGE_ALERTING:
2825                 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);
2826                 if (e_state!=EPOINT_STATE_OUT_SETUP
2827                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2828                  && e_state!=EPOINT_STATE_OUT_PROCEEDING)
2829                 {
2830                         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);
2831                         break;
2832                 }
2833                 port_alerting(portlist, message_type, param);
2834                 break;
2835
2836                 /* PORT sends CONNECT message */
2837                 case MESSAGE_CONNECT:
2838                 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);
2839                 if (e_state!=EPOINT_STATE_OUT_SETUP
2840                  && e_state!=EPOINT_STATE_OUT_OVERLAP
2841                  && e_state!=EPOINT_STATE_OUT_PROCEEDING
2842                  && e_state!=EPOINT_STATE_OUT_ALERTING)
2843                 {
2844                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2845                         break;
2846                 }
2847                 port_connect(portlist, message_type, param);
2848                 break;
2849
2850                 /* PORT sends DISCONNECT message */
2851                 case MESSAGE_DISCONNECT: /* port is disconnected */
2852                 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);
2853                 port_disconnect_release(portlist, message_type, param);
2854                 break;
2855
2856                 /* PORT sends a RELEASE message */
2857                 case MESSAGE_RELEASE: /* port releases */
2858                 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);
2859                 /* portlist is release at port_disconnect_release, thanx Paul */
2860                 port_disconnect_release(portlist, message_type, param);
2861                 break;
2862
2863                 /* PORT sends a TIMEOUT message */
2864                 case MESSAGE_TIMEOUT:
2865                 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);
2866                 port_timeout(portlist, message_type, param);
2867                 break; /* release */
2868
2869                 /* PORT sends a NOTIFY message */
2870                 case MESSAGE_NOTIFY:
2871                 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);
2872                 port_notify(portlist, message_type, param);
2873                 break;
2874
2875                 /* PORT sends a SUSPEND message */
2876                 case MESSAGE_SUSPEND:
2877                 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);
2878                 port_suspend(portlist, message_type, param);
2879                 break; /* suspend */
2880
2881                 /* PORT sends a RESUME message */
2882                 case MESSAGE_RESUME:
2883                 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);
2884                 port_resume(portlist, message_type, param);
2885                 break;
2886
2887                 default:
2888                 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);
2889         }
2890
2891         /* Note: this endpoint may be destroyed, so we MUST return */
2892 }
2893
2894
2895 /* messages from join
2896  */
2897 /* join MESSAGE_CRYPT */
2898 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2899 {
2900         switch(param->crypt.type)
2901         {
2902                 /* message from remote port to "crypt manager" */
2903                 case CU_ACTK_REQ:           /* activate key-exchange */
2904                 case CU_ACTS_REQ:            /* activate shared key */
2905                 case CU_DACT_REQ:          /* deactivate */
2906                 case CU_INFO_REQ:         /* request last info message */
2907                 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2908                 break;
2909
2910                 /* message from "crypt manager" to user */
2911                 case CU_ACTK_CONF:          /* key-echange done */
2912                 case CU_ACTS_CONF:          /* shared key done */
2913                 case CU_DACT_CONF:           /* deactivated */
2914                 case CU_DACT_IND:           /* deactivated */
2915                 case CU_ERROR_IND:         /* receive error message */
2916                 case CU_INFO_IND:         /* receive info message */
2917                 case CU_INFO_CONF:         /* receive info message */
2918                 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2919                 break;
2920
2921                 default:
2922                 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);
2923         }
2924 }
2925
2926 /* join MESSAGE_INFORMATION */
2927 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2928 {
2929         struct message *message;
2930
2931         e_overlap = 1;
2932
2933         while(portlist)
2934         {
2935                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2936                 memcpy(&message->param.information, &param->information, sizeof(struct dialing_info));
2937                 message_put(message);
2938                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2939                 portlist = portlist->next;
2940         }
2941 }
2942
2943 /* join MESSAGE_FACILITY */
2944 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2945 {
2946         struct message *message;
2947
2948         if (!e_ext.facility)
2949         {
2950                 return;
2951         }
2952
2953         while(portlist)
2954         {
2955                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2956                 memcpy(&message->param.facilityinfo, &param->facilityinfo, sizeof(struct facility_info));
2957                 message_put(message);
2958                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2959                 portlist = portlist->next;
2960         }
2961 }
2962
2963 /* join MESSAGE_MORE */
2964 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2965 {
2966         struct message *message;
2967
2968         new_state(EPOINT_STATE_IN_OVERLAP);
2969         
2970         /* own dialtone */
2971         if (e_join_pattern && e_ext.own_setup)
2972         {
2973                 /* disconnect audio */
2974                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
2975                 message->param.channel = CHANNEL_STATE_HOLD;
2976                 message_put(message);
2977         }
2978         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
2979         {
2980                         set_tone(portlist, "dialtone");
2981                         return;
2982         }
2983         if (e_ext.number[0])
2984                 set_tone(portlist, "dialpbx");
2985         else
2986                 set_tone(portlist, "dialtone");
2987 }
2988
2989 /* join MESSAGE_PROCEEDING */
2990 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2991 {
2992         struct message *message;
2993
2994         new_state(EPOINT_STATE_IN_PROCEEDING);
2995
2996         /* own proceeding tone */
2997         if (e_join_pattern)
2998         {
2999                 /* connect / disconnect audio */
3000                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3001                 if (e_ext.own_proceeding)
3002                         message->param.channel = CHANNEL_STATE_HOLD;
3003                 else
3004                         message->param.channel = CHANNEL_STATE_CONNECT;
3005                 message_put(message);
3006         }
3007 //                      UCPY(e_join_tone, "proceeding");
3008         if (portlist)
3009         {
3010                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3011                 message_put(message);
3012                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3013         }
3014         set_tone(portlist, "proceeding");
3015 }
3016
3017 /* join MESSAGE_ALERTING */
3018 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
3019 {
3020         struct message *message;
3021
3022         new_state(EPOINT_STATE_IN_ALERTING);
3023
3024         /* own alerting tone */
3025         if (e_join_pattern)
3026         {
3027                 /* connect / disconnect audio */
3028                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3029                 if (e_ext.own_alerting)
3030                         message->param.channel = CHANNEL_STATE_HOLD;
3031                 else
3032                         message->param.channel = CHANNEL_STATE_CONNECT;
3033                 message_put(message);
3034         }
3035         if (portlist)
3036         {
3037                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
3038                 message_put(message);
3039                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3040         }
3041         if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
3042         {
3043                 set_tone(portlist, "ringing");
3044                 return;
3045         }
3046         if (e_ext.number[0])
3047                 set_tone(portlist, "ringpbx");
3048         else
3049                 set_tone(portlist, "ringing");
3050 }
3051
3052 /* join MESSAGE_CONNECT */
3053 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
3054 {
3055         struct message *message;
3056         struct interface        *interface;
3057
3058         new_state(EPOINT_STATE_CONNECT);
3059 //                      UCPY(e_join_tone, "");
3060         if (e_ext.number[0])
3061                 e_dtmf = 1; /* allow dtmf */
3062         e_powerdialing = 0;
3063         memcpy(&e_connectinfo, &param->connectinfo, sizeof(e_callerinfo));
3064         if(portlist)
3065         {
3066                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3067                 memcpy(&message->param, param, sizeof(union parameter));
3068                 /* screen incoming caller id */
3069                 interface = interface_first;
3070                 while(interface)
3071                 {
3072                         if (!strcmp(e_connectinfo.interface, interface->name))
3073                         {
3074                                 break;
3075                         }
3076                         interface = interface->next;
3077                 }
3078                 if (interface)
3079                         screen(1, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
3080                 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(e_connectinfo));
3081
3082                 /* screen clip if prefix is required */
3083                 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0])
3084                 {
3085                         SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
3086                         SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype));
3087                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3088                 }
3089
3090                 /* use internal caller id */
3091                 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore))
3092                 {
3093                         SCPY(message->param.connectinfo.id, e_connectinfo.extension);
3094                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3095                 }
3096
3097                 /* handle restricted caller ids */
3098                 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);
3099                 /* display callerid if desired for extension */
3100                 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));
3101
3102                 /* use conp, if enabld */
3103                 if (!e_ext.centrex)
3104                         message->param.connectinfo.name[0] = '\0';
3105
3106                 /* send connect */
3107                 message_put(message);
3108                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3109         }
3110         set_tone(portlist, NULL);
3111         e_join_pattern = 0;
3112         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3113         message->param.channel = CHANNEL_STATE_CONNECT;
3114         message_put(message);
3115         e_start = now;
3116 }
3117
3118 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3119 void EndpointAppPBX::join_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
3120 {
3121         char cause[16];
3122         struct message *message;
3123
3124
3125         /* be sure that we are active */
3126         notify_active();
3127         e_tx_state = NOTIFY_STATE_ACTIVE;
3128
3129         /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
3130         if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1))
3131         {
3132                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
3133
3134                 /* set time for power dialing */
3135                 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
3136                 e_powercount++;
3137
3138                 /* set redial tone */
3139                 if (ea_endpoint->ep_portlist)
3140                 {
3141                         e_join_pattern = 0;
3142                 }
3143                 set_tone(ea_endpoint->ep_portlist, "redial");
3144                 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);
3145                 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3146                 if (e_state==EPOINT_STATE_IN_OVERLAP)
3147                 {
3148                         new_state(EPOINT_STATE_IN_PROCEEDING);
3149                         if (portlist)
3150                         {
3151                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3152                                 message_put(message);
3153                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3154                         }
3155 /* caused the error, that the first knock sound was not there */
3156 /*                                      set_tone(portlist, "proceeding"); */
3157                 }
3158                 /* send display of powerdialing */
3159                 if (e_ext.display_dialing)
3160                 {
3161                         while (portlist)
3162                         {
3163                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3164                                 if (e_powerlimit)
3165                                         SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3166                                 else
3167                                         SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3168                                 message_put(message);
3169                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3170                                 portlist = portlist->next;
3171                         }
3172                 }
3173                 return;
3174         }
3175
3176         /* set stop time */
3177         e_stop = now;
3178
3179         if ((e_state!=EPOINT_STATE_CONNECT
3180           && e_state!=EPOINT_STATE_OUT_DISCONNECT
3181           && e_state!=EPOINT_STATE_IN_OVERLAP
3182           && e_state!=EPOINT_STATE_IN_PROCEEDING
3183           && e_state!=EPOINT_STATE_IN_ALERTING)
3184          || !ea_endpoint->ep_portlist) /* or no port */
3185         {
3186                 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3187                 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */
3188                 return; /* must exit here */
3189         }
3190         /* save cause */
3191         if (!e_join_cause)
3192         {
3193                 e_join_cause = param->disconnectinfo.cause;
3194                 e_join_location = param->disconnectinfo.location;
3195         }
3196
3197         /* on release we need the audio again! */
3198         if (message_type == MESSAGE_RELEASE)
3199         {
3200                 e_join_pattern = 0;
3201                 ea_endpoint->ep_join_id = 0;
3202         }
3203         /* disconnect and select tone */
3204         new_state(EPOINT_STATE_OUT_DISCONNECT);
3205         SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3206         /* if own_cause, we must release the join */
3207         if (e_ext.own_cause /* own cause */
3208          || !e_join_pattern) /* no patterns */
3209         {
3210                 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);
3211                 if (message_type != MESSAGE_RELEASE)
3212                         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
3213                 e_join_pattern = 0;
3214         } else /* else we enable audio */
3215         {
3216                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3217                 message->param.channel = CHANNEL_STATE_CONNECT;
3218                 message_put(message);
3219         }
3220         /* send disconnect message */
3221         SCPY(e_tone, cause);
3222         while(portlist)
3223         {
3224                 set_tone(portlist, cause);
3225                 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3226                 portlist = portlist->next;
3227         }
3228 }
3229
3230 /* join MESSAGE_SETUP */
3231 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3232 {
3233         struct message *message;
3234         struct interface        *interface;
3235
3236         /* if we already in setup state, we just update the dialing with new digits */
3237         if (e_state == EPOINT_STATE_OUT_SETUP
3238          || e_state == EPOINT_STATE_OUT_OVERLAP)
3239         {
3240                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3241                 /* if digits changed, what we have already dialed */
3242                 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id)))
3243                 {
3244                         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);
3245                         /* release all ports */
3246                         while((portlist = ea_endpoint->ep_portlist))
3247                         {
3248                                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3249                                 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3250                                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3251                                 message_put(message);
3252                                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3253                                 ea_endpoint->free_portlist(portlist);
3254                         }
3255
3256                         /* disconnect audio */
3257                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3258                         message->param.channel = CHANNEL_STATE_HOLD;
3259                         message_put(message);
3260
3261                         /* get dialing info */
3262                         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3263                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3264                         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3265                         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3266                         new_state(EPOINT_STATE_OUT_OVERLAP);
3267
3268                         /* get time */
3269                         e_redial = now_d + 1; /* set redial one second in the future */
3270                         return;
3271                 }
3272                 /* if we have a pending redial, so we just adjust the dialing number */
3273                 if (e_redial)
3274                 {
3275                         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);
3276                         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3277                         return;
3278                 }
3279                 if (!ea_endpoint->ep_portlist)
3280                 {
3281                         PERROR("ERROR: overlap dialing to a NULL port relation\n");
3282                 }
3283                 if (ea_endpoint->ep_portlist->next)
3284                 {
3285                         PERROR("ERROR: overlap dialing to a port_list port relation\n");
3286                 }
3287                 if (e_state == EPOINT_STATE_OUT_SETUP)
3288                 {
3289                         /* queue digits */
3290                         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);
3291                         SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3292                         
3293                 } else
3294                 {
3295                         /* get what we have not dialed yet */
3296                         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));
3297                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3298                         SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3299                         message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3300                         message_put(message);
3301                         logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3302                 }
3303                 /* always store what we have dialed or queued */
3304                 memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3305                 
3306                 return;
3307         }
3308         if (e_state != EPOINT_STATE_IDLE)
3309         {
3310                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3311                 return;
3312         }
3313         /* if an internal extension is dialed, copy that number */
3314         if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3315                 SCPY(e_ext.number, param->setup.dialinginfo.id);
3316         /* if an internal extension is dialed, get extension's info about caller */
3317         if (e_ext.number[0]) 
3318         {
3319                 if (!read_extension(&e_ext, e_ext.number))
3320                 {
3321                         e_ext.number[0] = '\0';
3322                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3323                 }
3324         }
3325
3326         memcpy(&e_callerinfo, &param->setup.callerinfo, sizeof(e_callerinfo));
3327         memcpy(&e_dialinginfo, &param->setup.dialinginfo, sizeof(e_dialinginfo));
3328         memcpy(&e_redirinfo, &param->setup.redirinfo, sizeof(e_redirinfo));
3329         memcpy(&e_capainfo, &param->setup.capainfo, sizeof(e_capainfo));
3330
3331         /* screen incoming caller id */
3332         interface = interface_first;
3333         while(interface)
3334         {
3335                 if (!strcmp(e_callerinfo.interface, interface->name))
3336                 {
3337                         break;
3338                 }
3339                 interface = interface->next;
3340         }
3341         if (interface)
3342                 screen(1, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
3343
3344         /* process (voice over) data calls */
3345         if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO)
3346         {
3347                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3348                 memset(&e_capainfo, 0, sizeof(e_capainfo));
3349                 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3350                 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3351                 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3352         }
3353
3354         new_state(EPOINT_STATE_OUT_SETUP);
3355         /* call special setup routine */
3356         out_setup();
3357 }
3358
3359 /* join MESSAGE_mISDNSIGNAL */
3360 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3361 {
3362         struct message *message;
3363
3364         while(portlist)
3365         {
3366                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3367                 memcpy(&message->param, param, sizeof(union parameter));
3368                 message_put(message);
3369                 portlist = portlist->next;
3370         }
3371 }
3372
3373 /* join MESSAGE_NOTIFY */
3374 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3375 {
3376         struct message *message;
3377         int new_state;
3378
3379         if (param->notifyinfo.notify)
3380         {
3381                 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3382 //              /* if notification was generated locally, we turn hold music on/off */ 
3383 //              if (param->notifyinfo.local)
3384 // 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)
3385                 {
3386                         if (e_hold)
3387                         {
3388                                 /* unhold if */
3389                                 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND)
3390                                 {
3391                                         while(portlist)
3392                                         {
3393                                                 set_tone(portlist, "");
3394                                                 portlist = portlist->next;
3395                                         }
3396                                         portlist = ea_endpoint->ep_portlist;
3397                                         e_hold = 0;
3398                                 }
3399                         } else {
3400                                 /* hold if */
3401                                 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND)
3402                                 {
3403                                         while(portlist)
3404                                         {
3405                                                 set_tone(portlist, "hold");
3406                                                 portlist = portlist->next;
3407                                         }
3408                                         portlist = ea_endpoint->ep_portlist;
3409                                         e_hold = 1;
3410                                 }
3411                         }
3412                 }
3413                 /* save new state */
3414                 e_tx_state = new_state;
3415         }
3416
3417         /* notify port(s) about it */
3418         while(portlist)
3419         {
3420                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3421                 memcpy(&message->param.notifyinfo, &param->notifyinfo, sizeof(struct notify_info));
3422                 /* handle restricted caller ids */
3423                 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);
3424                 /* display callerid if desired for extension */
3425                 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));
3426                 message_put(message);
3427                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3428                 portlist = portlist->next;
3429         }
3430 }
3431
3432 /* call sends messages to the endpoint
3433  */
3434 void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, union parameter *param)
3435 {
3436         struct port_list *portlist;
3437         struct message *message;
3438
3439         if (!join_id)
3440         {
3441                 PERROR("EPOINT(%d) error: call == NULL.\n", ea_endpoint->ep_serial);
3442                 return;
3443         }
3444
3445         portlist = ea_endpoint->ep_portlist;
3446
3447         /* send MESSAGE_DATA to port */
3448         if (message_type == MESSAGE_DATA)
3449         {
3450                 if (join_id == ea_endpoint->ep_join_id) // still linked with call
3451                 {
3452                         /* skip if no port relation */
3453                         if (!portlist)
3454                                 return;
3455                         /* skip if more than one port relation */
3456                         if (portlist->next)
3457                                 return;
3458                         /* forward audio data to port */
3459                         message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3460                         return;
3461                 }
3462         }
3463
3464 //      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);
3465         switch(message_type)
3466         {
3467                 /* CALL SENDS CRYPT message */
3468                 case MESSAGE_CRYPT:
3469                 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);
3470                 join_crypt(portlist, message_type, param);
3471                 break;
3472
3473                 /* CALL sends INFORMATION message */
3474                 case MESSAGE_INFORMATION:
3475                 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);
3476                 join_information(portlist, message_type, param);
3477                 break;
3478
3479                 /* CALL sends FACILITY message */
3480                 case MESSAGE_FACILITY:
3481                 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);
3482                 join_facility(portlist, message_type, param);
3483                 break;
3484
3485                 /* CALL sends OVERLAP message */
3486                 case MESSAGE_OVERLAP:
3487                 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);
3488                 if (e_state!=EPOINT_STATE_IN_SETUP
3489                  && e_state!=EPOINT_STATE_IN_OVERLAP)
3490                 {
3491                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3492                         break;
3493                 }
3494                 join_overlap(portlist, message_type, param);
3495                 break;
3496
3497                 /* CALL sends PROCEEDING message */
3498                 case MESSAGE_PROCEEDING:
3499                 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);
3500                 if(e_state!=EPOINT_STATE_IN_OVERLAP)
3501                 {
3502                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3503                         break;
3504                 }
3505                 join_proceeding(portlist, message_type, param);
3506                 break;
3507
3508                 /* CALL sends ALERTING message */
3509                 case MESSAGE_ALERTING:
3510                 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);
3511                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3512                  && e_state!=EPOINT_STATE_IN_PROCEEDING)
3513                 {
3514                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3515                         break;
3516                 }
3517                 join_alerting(portlist, message_type, param);
3518                 break;
3519
3520                 /* CALL sends CONNECT message */
3521                 case MESSAGE_CONNECT:
3522                 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);
3523                 if (e_state!=EPOINT_STATE_IN_OVERLAP
3524                  && e_state!=EPOINT_STATE_IN_PROCEEDING
3525                  && e_state!=EPOINT_STATE_IN_ALERTING)
3526                 {
3527                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3528                         break;
3529                 }
3530                 join_connect(portlist, message_type, param);
3531                 break;
3532
3533                 /* CALL sends DISCONNECT/RELEASE message */
3534                 case MESSAGE_DISCONNECT: /* call disconnect */
3535                 case MESSAGE_RELEASE: /* call releases */
3536                 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);
3537                 join_disconnect_release(portlist, message_type, param);
3538                 break;
3539
3540                 /* CALL sends SETUP message */
3541                 case MESSAGE_SETUP:
3542                 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);
3543                 join_setup(portlist, message_type, param);
3544                 return;
3545                 break;
3546
3547                 /* CALL sends special mISDNSIGNAL message */
3548                 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3549                 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);
3550                 join_mISDNsignal(portlist, message_type, param);
3551                 break;
3552
3553                 /* CALL has pattern available */
3554                 case MESSAGE_PATTERN: /* indicating pattern available */
3555                 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);
3556                 if (!e_join_pattern)
3557                 {
3558                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3559                         e_join_pattern = 1;
3560                         SCPY(e_tone, "");
3561                         while(portlist)
3562                         {
3563                                 set_tone(portlist, NULL);
3564                                 portlist = portlist->next;
3565                         }
3566                         /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3567                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3568                         message->param.channel = CHANNEL_STATE_CONNECT;
3569                         message_put(message);
3570 //                      /* tell remote epoint to connect audio also, because we like to hear the patterns */
3571 //                      message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_REMOTE_AUDIO);
3572 //                      message->param.channel = CHANNEL_STATE_CONNECT;
3573 //                      message_put(message);
3574 // patterns are available, remote already connected audio
3575                 }
3576                 break;
3577
3578                 /* CALL has no pattern available */
3579                 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3580                 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);
3581                 if (e_join_pattern)
3582                 {
3583                         PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3584                         e_join_pattern = 0;
3585                         /* disconnect our audio tx and rx */
3586                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3587                         message->param.channel = CHANNEL_STATE_HOLD;
3588                         message_put(message);
3589                 }
3590                 break;
3591
3592 #if 0
3593                 /* CALL (dunno at the moment) */
3594                 case MESSAGE_REMOTE_AUDIO:
3595                 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);
3596                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3597                 message->param.channel = param->channel;
3598                 message_put(message);
3599                 break;
3600 #endif
3601
3602                 /* CALL sends a notify message */
3603                 case MESSAGE_NOTIFY:
3604                 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);
3605                 join_notify(portlist, message_type, param);
3606                 break;
3607
3608                 default:
3609                 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);
3610         }
3611 }
3612
3613
3614 /* pick_join will connect the first incoming call found. the endpoint
3615  * will receivce a MESSAGE_CONNECT.
3616  */
3617 int match_list(char *list, char *item)
3618 {
3619         char *end, *next = NULL;
3620
3621         /* no list make matching */
3622         if (!list)
3623                 return(1);
3624
3625         while(42)
3626         {
3627                 /* eliminate white spaces */
3628                 while (*list <= ' ')
3629                         list++;
3630                 if (*list == ',')
3631                 {
3632                         list++;
3633                         continue;
3634                 }
3635                 /* if end of list is reached, we return */
3636                 if (list[0] == '\0')
3637                         return(0);
3638                 /* if we have more than one entry (left) */
3639                 if ((end = strchr(list, ',')))
3640                         next = end + 1;
3641                 else
3642                         next = end = strchr(list, '\0');
3643                 while (*(end-1) <= ' ')
3644                         end--;
3645                 /* if string part matches item */
3646                 if (!strncmp(list, item, end-list))
3647                         return(1);
3648                 list = next;
3649         }
3650 }
3651
3652 void EndpointAppPBX::pick_join(char *extensions)
3653 {
3654         struct message *message;
3655         struct port_list *portlist;
3656         class Port *port;
3657         class EndpointAppPBX *eapp, *found;
3658         class Join *join;
3659         class JoinPBX *joinpbx;
3660         struct join_relation *relation;
3661         int vbox;
3662
3663         /* find an endpoint that is ringing internally or vbox with higher priority */
3664         vbox = 0;
3665         found = NULL;
3666         eapp = apppbx_first;
3667         while(eapp)
3668         {
3669                 if (eapp!=this && ea_endpoint->ep_portlist)
3670                 {
3671                         portlist = eapp->ea_endpoint->ep_portlist;
3672                         while(portlist)
3673                         {
3674                                 if ((port = find_port_id(portlist->port_id)))
3675                                 {
3676                                         if (port->p_type == PORT_TYPE_VBOX_OUT)
3677                                         {
3678                                                 if (match_list(extensions, eapp->e_ext.number))
3679                                                 {
3680                                                         found = eapp;
3681                                                         vbox = 1;
3682                                                         break;
3683                                                 }
3684                                         }
3685                                         if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT)
3686                                          && port->p_state==PORT_STATE_OUT_ALERTING)
3687                                                 if (match_list(extensions, eapp->e_ext.number))
3688                                                 {
3689                                                         found = eapp;
3690                                                 }
3691                                 }
3692                                 portlist = portlist->next;
3693                         }
3694                         if (portlist)
3695                                 break;
3696                 }
3697                 eapp = eapp->next;
3698         }
3699
3700         /* if no endpoint found */
3701         if (!found)
3702         {
3703                 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);
3704 reject:
3705                 set_tone(ea_endpoint->ep_portlist, "cause_10");
3706                 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3707                 new_state(EPOINT_STATE_OUT_DISCONNECT);
3708                 return;
3709         }
3710         eapp = found;
3711
3712         if (ea_endpoint->ep_join_id)
3713         {
3714                 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3715                 goto reject;
3716         }
3717         if (!eapp->ea_endpoint->ep_join_id)
3718         {
3719                 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3720                 goto reject;
3721         }
3722         join = find_join_id(eapp->ea_endpoint->ep_join_id);
3723         if (!join)
3724         {
3725                 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3726                 goto reject;
3727         }
3728         if (joinpbx->c_type != JOIN_TYPE_PBX)
3729         {
3730                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3731                 goto reject;
3732         }
3733         joinpbx = (class JoinPBX *)join;
3734         relation = joinpbx->c_relation;
3735         if (!relation)
3736         {
3737                 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3738                 goto reject;
3739         }
3740         while (relation->epoint_id != eapp->ea_endpoint->ep_serial)
3741         {
3742                 relation = relation->next;
3743                 if (!relation)
3744                 {
3745                         PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3746                         goto reject;
3747                 }
3748         }
3749
3750         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3751
3752         if (options.deb & DEBUG_EPOINT)
3753         {
3754                 class Join *debug_c = join_first;
3755                 class Endpoint *debug_e = epoint_first;
3756                 class Port *debug_p = port_first;
3757
3758                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3759
3760                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3761                 while(debug_c)
3762                 {
3763                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->c_serial);
3764                         debug_c = debug_c->next;
3765                 }
3766                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3767                 while(debug_e)
3768                 {
3769                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3770                         debug_e = debug_e->next;
3771                 }
3772                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3773                 while(debug_p)
3774                 {
3775                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3776                         debug_p = debug_p->next;
3777                 }
3778         }
3779
3780         /* relink join */
3781         ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3782         relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3783         eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3784
3785         /* connnecting our endpoint */
3786         new_state(EPOINT_STATE_CONNECT);
3787         e_dtmf = 1;
3788         set_tone(ea_endpoint->ep_portlist, NULL);
3789
3790         /* now we send a release to the ringing endpoint */
3791         message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3792         message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3793         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3794         message_put(message);
3795
3796         /* we send a connect to the join with our caller id */
3797         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3798         SCPY(message->param.connectinfo.id, e_callerinfo.id);
3799         message->param.connectinfo.present = e_callerinfo.present;
3800         message->param.connectinfo.screen = e_callerinfo.screen;
3801         message->param.connectinfo.itype = e_callerinfo.itype;
3802         message->param.connectinfo.ntype = e_callerinfo.ntype;
3803         message_put(message);
3804
3805         /* we send a connect to our port with the remote callerid */
3806         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3807         SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3808         message->param.connectinfo.present = eapp->e_callerinfo.present;
3809         message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3810         message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3811         message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3812         /* handle restricted caller ids */
3813         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);
3814         /* display callerid if desired for extension */
3815         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));
3816         message_put(message);
3817
3818         /* we send a connect to the audio path (not for vbox) */
3819         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CHANNEL);
3820         message->param.channel = CHANNEL_STATE_CONNECT;
3821         message_put(message);
3822
3823         /* beeing paranoid, we make call update */
3824         joinpbx->c_updatebridge = 1;
3825
3826         if (options.deb & DEBUG_EPOINT)
3827         {
3828                 class Join *debug_c = join_first;
3829                 class Endpoint *debug_e = epoint_first;
3830                 class Port *debug_p = port_first;
3831
3832                 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3833
3834                 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3835                 while(debug_c)
3836                 {
3837                         PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->c_serial);
3838                         debug_c = debug_c->next;
3839                 }
3840                 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3841                 while(debug_e)
3842                 {
3843                         PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3844                         debug_e = debug_e->next;
3845                 }
3846                 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3847                 while(debug_p)
3848                 {
3849                         PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3850                         debug_p = debug_p->next;
3851                 }
3852         }
3853 }
3854
3855
3856 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3857  */
3858 void EndpointAppPBX::join_join(void)
3859 {
3860         struct message *message;
3861         struct join_relation *our_relation, *other_relation;
3862         struct join_relation **our_relation_pointer, **other_relation_pointer;
3863         class Join *our_join, *other_join;
3864         class JoinPBX *our_joinpbx, *other_joinpbx;
3865         class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3866         class Port *our_port, *other_port;
3867         class Pdss1 *our_pdss1, *other_pdss1;
3868
3869         /* are we a candidate to join a join */
3870         our_join = find_join_id(ea_endpoint->ep_join_id);
3871         if (!our_join)
3872         {
3873                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3874                 return;
3875         }
3876         if (our_join->c_type != JOIN_TYPE_PBX)
3877         {
3878                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3879                 return;
3880         }
3881         our_joinpbx = (class JoinPBX *)our_join;
3882         if (!ea_endpoint->ep_portlist)
3883         {
3884                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3885                 return;
3886         }
3887         if (!e_ext.number[0])
3888         {
3889                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3890                 return;
3891         }
3892         our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3893         if (!our_port)
3894         {
3895                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3896                 return;
3897         }
3898         if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
3899         {
3900                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3901                 return;
3902         }
3903         our_pdss1 = (class Pdss1 *)our_port;
3904
3905         /* find an endpoint that is on hold and has the same mISDNport that we are on */
3906         other_eapp = apppbx_first;
3907         while(other_eapp)
3908         {
3909                 if (other_eapp == this)
3910                 {
3911                         other_eapp = other_eapp->next;
3912                         continue;
3913                 }
3914                 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);
3915                 if (other_eapp->e_ext.number[0] /* has terminal */
3916                  && other_eapp->ea_endpoint->ep_portlist /* has port */
3917                  && other_eapp->ea_endpoint->ep_join_id) /* has join */
3918                 {
3919                         other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3920                         if (other_port) /* port still exists */
3921                         {
3922                                 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3923                                  || other_port->p_type==PORT_TYPE_DSS1_NT_IN) /* port is isdn nt-mode */
3924                                 {
3925                                         other_pdss1 = (class Pdss1 *)other_port;
3926                                         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);
3927                                         if (other_pdss1->p_m_hold /* port is on hold */
3928                                          && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3929                                          && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3930                                                 break;
3931                                 } else
3932                                 {
3933                                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3934                                 }
3935                         } else
3936                         {
3937                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3938                         }
3939                 }
3940                 other_eapp = other_eapp->next;
3941         }
3942         if (!other_eapp)
3943         {
3944                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn interface with port on hold.\n", ea_endpoint->ep_serial);
3945                 return;
3946         }
3947         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port on hold found.\n", ea_endpoint->ep_serial);
3948
3949         /* if we have the same join */
3950         if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id)
3951         {
3952                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we an the other have the same join.\n", ea_endpoint->ep_serial);
3953                 return;
3954         }
3955         other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3956         if (!other_join)
3957         {
3958                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3959                 return;
3960         }
3961         if (other_join->c_type != JOIN_TYPE_PBX)
3962         {
3963                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3964                 return;
3965         }
3966         other_joinpbx = (class JoinPBX *)other_join;
3967         if (our_joinpbx->c_partyline && other_joinpbx->c_partyline)
3968         {
3969                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3970                 return;
3971         }
3972
3973         /* remove relation to endpoint for join on hold */
3974         other_relation = other_joinpbx->c_relation;
3975         other_relation_pointer = &other_joinpbx->c_relation;
3976         while(other_relation)
3977         {
3978                 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial)
3979                 {
3980                 /* detach other endpoint on hold */
3981                         *other_relation_pointer = other_relation->next;
3982                         FREE(other_relation, sizeof(struct join_relation));
3983                         cmemuse--;
3984                         other_relation = *other_relation_pointer;
3985                         other_eapp->ea_endpoint->ep_join_id = NULL;
3986                         continue;
3987                 }
3988
3989                 /* change join/hold pointer of endpoint to the new join */
3990                 temp_epoint = find_epoint_id(other_relation->epoint_id);
3991                 if (temp_epoint)
3992                 {
3993                         if (temp_epoint->ep_join_id == other_join->c_serial)
3994                                 temp_epoint->ep_join_id = our_join->c_serial;
3995                 }
3996
3997                 other_relation_pointer = &other_relation->next;
3998                 other_relation = other_relation->next;
3999         }
4000         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
4001
4002         /* join call relations */
4003         our_relation = our_joinpbx->c_relation;
4004         our_relation_pointer = &our_joinpbx->c_relation;
4005         while(our_relation)
4006         {
4007                 our_relation_pointer = &our_relation->next;
4008                 our_relation = our_relation->next;
4009         }
4010         *our_relation_pointer = other_joinpbx->c_relation;
4011         other_joinpbx->c_relation = NULL;
4012         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
4013
4014         /* release endpoint on hold */
4015         message = message_create(other_joinpbx->c_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
4016         message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
4017         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
4018         message_put(message);
4019         
4020         /* if we are not a partyline, we get partyline state from other join */
4021         our_joinpbx->c_partyline += other_joinpbx->c_partyline; 
4022
4023         /* remove empty join */
4024         delete other_join;
4025         PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
4026
4027         /* mixer must update */
4028         our_joinpbx->c_updatebridge = 1; /* update mixer flag */
4029
4030         /* we send a retrieve to that endpoint */
4031         // mixer will update the hold-state of the join and send it to the endpoints is changes
4032 }
4033
4034
4035 /* check if we have an external call
4036  * this is used to check for encryption ability
4037  */
4038 int EndpointAppPBX::check_external(char **errstr, class Port **port)
4039 {
4040         struct join_relation *relation;
4041         class Join *join;
4042         class JoinPBX *joinpbx;
4043         class Endpoint *epoint;
4044
4045         /* some paranoia check */
4046         if (!ea_endpoint->ep_portlist)
4047         {
4048                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4049                 *errstr = "No Call";
4050                 return(1);
4051         }
4052         if (!e_ext.number[0])
4053         {
4054                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4055                 *errstr = "No Call";
4056                 return(1);
4057         }
4058
4059         /* check if we have a join with 2 parties */
4060         join = find_join_id(ea_endpoint->ep_join_id);
4061         if (!join)
4062         {
4063                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
4064                 *errstr = "No Call";
4065                 return(1);
4066         }
4067         if (join->c_type != JOIN_TYPE_PBX)
4068         {
4069                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4070                 *errstr = "No PBX Call";
4071                 return(1);
4072         }
4073         joinpbx = (class JoinPBX *)join;
4074         relation = joinpbx->c_relation;
4075         if (!relation)
4076         {
4077                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4078                 *errstr = "No Call";
4079                 return(1);
4080         }
4081         if (!relation->next)
4082         {
4083                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4084                 *errstr = "No Call";
4085                 return(1);
4086         }
4087         if (relation->next->next)
4088         {
4089                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4090                 *errstr = "Err: Conference";
4091                 return(1);
4092         }
4093         if (relation->epoint_id == ea_endpoint->ep_serial)
4094         {
4095                 relation = relation->next;
4096                 if (relation->epoint_id == ea_endpoint->ep_serial)
4097                 {
4098                         PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4099                         *errstr = "Software Error";
4100                         return(1);
4101                 }
4102         }
4103
4104         /* check remote port for external call */
4105         epoint = find_epoint_id(relation->epoint_id);
4106         if (!epoint)
4107         {
4108                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4109                 *errstr = "No Call";
4110                 return(1);
4111         }
4112         if (!epoint->ep_portlist)
4113         {
4114                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4115                 *errstr = "No Call";
4116                 return(1);
4117         }
4118         *port = find_port_id(epoint->ep_portlist->port_id);
4119         if (!(*port))
4120         {
4121                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4122                 *errstr = "No Call";
4123                 return(1);
4124         }
4125         if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) /* port is not external isdn */
4126         {
4127                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4128                 *errstr = "No Ext Call";
4129                 return(1);
4130         }
4131         if ((*port)->p_state != PORT_STATE_CONNECT)
4132         {
4133                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4134                 *errstr = "No Ext Connect";
4135                 return(1);
4136         }
4137         return(0);
4138 }
4139
4140 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned long port_id, int dir)
4141 {
4142         char *logtext = "unknown";
4143         char buffer[64];
4144
4145         switch(message_type)
4146         {
4147                 case MESSAGE_SETUP:
4148                 trace_header("SETUP", dir);
4149                 if (dir == DIRECTION_OUT)
4150                         add_trace("to", NULL, "CH(%lu)", port_id);
4151                 if (dir == DIRECTION_IN)
4152                         add_trace("from", NULL, "CH(%lu)", port_id);
4153                 if (param->setup.callerinfo.extension[0])
4154                         add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4155                 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype));
4156                 switch(param->setup.callerinfo.present)
4157                 {
4158                         case INFO_PRESENT_RESTRICTED:
4159                         add_trace("caller id", "present", "restricted");
4160                         break;
4161                         case INFO_PRESENT_ALLOWED:
4162                         add_trace("caller id", "present", "allowed");
4163                         break;
4164                         default:
4165                         add_trace("caller id", "present", "not available");
4166                 }
4167                 if (param->setup.redirinfo.id[0])
4168                 {
4169                         add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype));
4170                         switch(param->setup.redirinfo.present)
4171                         {
4172                                 case INFO_PRESENT_RESTRICTED:
4173                                 add_trace("redir'ing", "present", "restricted");
4174                                 break;
4175                                 case INFO_PRESENT_ALLOWED:
4176                                 add_trace("redir'ing", "present", "allowed");
4177                                 break;
4178                                 default:
4179                                 add_trace("redir'ing", "present", "not available");
4180                         }
4181                 }
4182                 if (param->setup.dialinginfo.id[0])
4183                         add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4184                 end_trace();
4185                 break;
4186
4187                 case MESSAGE_OVERLAP:
4188                 trace_header("SETUP ACKNOWLEDGE", dir);
4189                 if (dir == DIRECTION_OUT)
4190                         add_trace("to", NULL, "CH(%lu)", port_id);
4191                 if (dir == DIRECTION_IN)
4192                         add_trace("from", NULL, "CH(%lu)", port_id);
4193                 end_trace();
4194                 break;
4195
4196                 case MESSAGE_PROCEEDING:
4197                 trace_header("PROCEEDING", dir);
4198                 if (dir == DIRECTION_OUT)
4199                         add_trace("to", NULL, "CH(%lu)", port_id);
4200                 if (dir == DIRECTION_IN)
4201                         add_trace("from", NULL, "CH(%lu)", port_id);
4202                 end_trace();
4203                 break;
4204
4205                 case MESSAGE_ALERTING:
4206                 trace_header("ALERTING", dir);
4207                 if (dir == DIRECTION_OUT)
4208                         add_trace("to", NULL, "CH(%lu)", port_id);
4209                 if (dir == DIRECTION_IN)
4210                         add_trace("from", NULL, "CH(%lu)", port_id);
4211                 end_trace();
4212                 break;
4213
4214                 case MESSAGE_CONNECT:
4215                 trace_header("CONNECT", dir);
4216                 if (dir == DIRECTION_OUT)
4217                         add_trace("to", NULL, "CH(%lu)", port_id);
4218                 if (dir == DIRECTION_IN)
4219                         add_trace("from", NULL, "CH(%lu)", port_id);
4220                 if (param->connectinfo.extension[0])
4221                         add_trace("extension", NULL, "%s", param->connectinfo.extension);
4222                 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype));
4223                 switch(param->connectinfo.present)
4224                 {
4225                         case INFO_PRESENT_RESTRICTED:
4226                         add_trace("connect id", "present", "restricted");
4227                         break;
4228                         case INFO_PRESENT_ALLOWED:
4229                         add_trace("connect id", "present", "allowed");
4230                         break;
4231                         default:
4232                         add_trace("connect id", "present", "not available");
4233                 }
4234                 end_trace();
4235                 break;
4236
4237                 case MESSAGE_DISCONNECT:
4238                 case MESSAGE_RELEASE:
4239                 if (message_type == MESSAGE_DISCONNECT)
4240                         trace_header("DISCONNECT", dir);
4241                 else
4242                         trace_header("RELEASE", dir);
4243                 if (dir == DIRECTION_OUT)
4244                         add_trace("to", NULL, "CH(%lu)", port_id);
4245                 if (dir == DIRECTION_IN)
4246                         add_trace("from", NULL, "CH(%lu)", port_id);
4247                 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4248                 switch(param->disconnectinfo.location)
4249                 {
4250                         case LOCATION_USER:
4251                         add_trace("cause", "location", "0-User");
4252                         break;
4253                         case LOCATION_PRIVATE_LOCAL:
4254                         add_trace("cause", "location", "1-Local-PBX");
4255                         break;
4256                         case LOCATION_PUBLIC_LOCAL:
4257                         add_trace("cause", "location", "2-Local-Exchange");
4258                         break;
4259                         case LOCATION_TRANSIT:
4260                         add_trace("cause", "location", "3-Transit");
4261                         break;
4262                         case LOCATION_PUBLIC_REMOTE:
4263                         add_trace("cause", "location", "4-Remote-PBX");
4264                         break;
4265                         case LOCATION_PRIVATE_REMOTE:
4266                         add_trace("cause", "location", "5-Remote-Exchange");
4267                         break;
4268                         case LOCATION_INTERNATIONAL:
4269                         add_trace("cause", "location", "7-International-Exchange");
4270                         break;
4271                         case LOCATION_BEYOND:
4272                         add_trace("cause", "location", "10-Beyond-Interworking");
4273                         break;
4274                         default:
4275                         add_trace("cause", "location", "%d", param->disconnectinfo.location);
4276                 }
4277                 end_trace();
4278                 break;
4279
4280                 case MESSAGE_NOTIFY:
4281                 switch(param->notifyinfo.notify)
4282                 {
4283                         case 0x00:
4284                         logtext = "NULL";
4285                         break;
4286                         case 0x80:
4287                         logtext = "USER_SUSPENDED";
4288                         break;
4289                         case 0x82:
4290                         logtext = "BEARER_SERVICE_CHANGED";
4291                         break;
4292                         case 0x81:
4293                         logtext = "USER_RESUMED";
4294                         break;
4295                         case 0xc2:
4296                         logtext = "CONFERENCE_ESTABLISHED";
4297                         break;
4298                         case 0xc3:
4299                         logtext = "CONFERENCE_DISCONNECTED";
4300                         break;
4301                         case 0xc4:
4302                         logtext = "OTHER_PARTY_ADDED";
4303                         break;
4304                         case 0xc5:
4305                         logtext = "ISOLATED";
4306                         break;
4307                         case 0xc6:
4308                         logtext = "REATTACHED";
4309                         break;
4310                         case 0xc7:
4311                         logtext = "OTHER_PARTY_ISOLATED";
4312                         break;
4313                         case 0xc8:
4314                         logtext = "OTHER_PARTY_REATTACHED";
4315                         break;
4316                         case 0xc9:
4317                         logtext = "OTHER_PARTY_SPLIT";
4318                         break;
4319                         case 0xca:
4320                         logtext = "OTHER_PARTY_DISCONNECTED";
4321                         break;
4322                         case 0xcb:
4323                         logtext = "CONFERENCE_FLOATING";
4324                         break;
4325                         case 0xcc:
4326                         logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4327                         break;
4328                         case 0xcf:
4329                         logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4330                         break;
4331                         case 0xe0:
4332                         logtext = "CALL_IS_A_WAITING_CALL";
4333                         break;
4334                         case 0xe8:
4335                         logtext = "DIVERSION_ACTIVATED";
4336                         break;
4337                         case 0xe9:
4338                         logtext = "RESERVED_CT_1";
4339                         break;
4340                         case 0xea:
4341                         logtext = "RESERVED_CT_2";
4342                         break;
4343                         case 0xee:
4344                         logtext = "REVERSE_CHARGING";
4345                         break;
4346                         case 0xf9:
4347                         logtext = "REMOTE_HOLD";
4348                         break;
4349                         case 0xfa:
4350                         logtext = "REMOTE_RETRIEVAL";
4351                         break;
4352                         case 0xfb:
4353                         logtext = "CALL_IS_DIVERTING";
4354                         break;
4355                         default:
4356                         SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4357                         logtext = buffer;
4358
4359                 }
4360                 trace_header("NOTIFY", dir);
4361                 if (dir == DIRECTION_OUT)
4362                         add_trace("to", NULL, "CH(%lu)", port_id);
4363                 if (dir == DIRECTION_IN)
4364                         add_trace("from", NULL, "CH(%lu)", port_id);
4365                 if (param->notifyinfo.notify)
4366                         add_trace("indicator", NULL, "%s", logtext);
4367                 if (param->notifyinfo.id[0])
4368                 {
4369                         add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype));
4370                         switch(param->notifyinfo.present)
4371                         {
4372                                 case INFO_PRESENT_RESTRICTED:
4373                                 add_trace("redir'on", "present", "restricted");
4374                                 break;
4375                                 case INFO_PRESENT_ALLOWED:
4376                                 add_trace("redir'on", "present", "allowed");
4377                                 break;
4378                                 default:
4379                                 add_trace("redir'on", "present", "not available");
4380                         }
4381                 }
4382                 if (param->notifyinfo.display[0])
4383                         add_trace("display", NULL, "%s", param->notifyinfo.display);
4384                 end_trace();
4385                 break;
4386
4387                 case MESSAGE_INFORMATION:
4388                 trace_header("INFORMATION", dir);
4389                 if (dir == DIRECTION_OUT)
4390                         add_trace("to", NULL, "CH(%lu)", port_id);
4391                 if (dir == DIRECTION_IN)
4392                         add_trace("from", NULL, "CH(%lu)", port_id);
4393                 add_trace("dialing", NULL, "%s", param->information.id);
4394                 end_trace();
4395                 break;
4396
4397                 case MESSAGE_FACILITY:
4398                 trace_header("FACILITY", dir);
4399                 if (dir == DIRECTION_OUT)
4400                         add_trace("to", NULL, "CH(%lu)", port_id);
4401                 if (dir == DIRECTION_IN)
4402                         add_trace("from", NULL, "CH(%lu)", port_id);
4403                 end_trace();
4404                 break;
4405
4406                 case MESSAGE_TONE:
4407                 trace_header("TONE", dir);
4408                 if (dir == DIRECTION_OUT)
4409                         add_trace("to", NULL, "CH(%lu)", port_id);
4410                 if (dir == DIRECTION_IN)
4411                         add_trace("from", NULL, "CH(%lu)", port_id);
4412                 if (param->tone.name[0])
4413                 {
4414                         add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4415                         add_trace("name", NULL, "%s", param->tone.name);
4416                 } else
4417                         add_trace("off", NULL, NULL);
4418                 end_trace();
4419                 break;
4420
4421                 case MESSAGE_SUSPEND:
4422                 case MESSAGE_RESUME:
4423                 if (message_type == MESSAGE_SUSPEND)
4424                         trace_header("SUSPEND", dir);
4425                 else
4426                         trace_header("RESUME", dir);
4427                 if (dir == DIRECTION_OUT)
4428                         add_trace("to", NULL, "CH(%lu)", port_id);
4429                 if (dir == DIRECTION_IN)
4430                         add_trace("from", NULL, "CH(%lu)", port_id);
4431                 if (param->parkinfo.len)
4432                         add_trace("length", NULL, "%d", param->parkinfo.len);
4433                 end_trace();
4434                 break;
4435
4436                 default:
4437                 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4438         }
4439 }
4440
4441 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, char *display)
4442 {
4443         struct message *message;
4444
4445         if (!portlist)
4446                 return;
4447         if (!portlist->port_id)
4448                 return;
4449
4450         if (!e_connectedmode)
4451         {
4452                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4453                 message->param.disconnectinfo.cause = cause;
4454                 message->param.disconnectinfo.location = location;
4455                 if (display[0])
4456                         SCPY(message->param.disconnectinfo.display, display);
4457                 else
4458                         SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4459         } else
4460         {
4461                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4462                 if (display[0])
4463                         SCPY(message->param.notifyinfo.display, display);
4464                 else
4465                         SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4466         }
4467         message_put(message);
4468         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
4469 }
4470
4471