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