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