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