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