Minor fix in interface.conf example
[lcr.git] / action.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** all actions (and hangup) are processed here                               **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 extern char **environ;
15
16
17 /*
18  * process init 'internal' / 'external' / 'remote' / 'vbox-record' / 'partyline'...
19  */
20 int EndpointAppPBX::_action_init_call(char *remote)
21 {
22         class Join              *join;
23         struct port_list        *portlist = ea_endpoint->ep_portlist;
24         struct admin_list       *admin;
25
26         /* a created call, this should never happen */
27         if (ea_endpoint->ep_join_id) {
28                 if (options.deb & DEBUG_EPOINT)
29                         PERROR("EPOINT(%d): We already have a call instance, this should never happen!\n", ea_endpoint->ep_serial);
30                 return(0);
31         }
32
33         /* create join */
34         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new join instance.\n", ea_endpoint->ep_serial);
35         if (remote) {
36                 admin = admin_first;
37                 while(admin) {
38                         if (admin->remote_name[0] && !strcmp(admin->remote_name, remote))
39                                 break;
40                         admin = admin->next;
41                 }
42                 if (!admin) {
43                         /* resource not available */
44                         trace_header("ACTION remote (not available)", DIRECTION_NONE);
45                         add_trace("application", NULL, "%s", remote);
46                         end_trace();
47                         message_disconnect_port(portlist, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, "");
48                         new_state(EPOINT_STATE_OUT_DISCONNECT);
49                         set_tone(portlist,"cause_1b");
50                         return(0);
51                 }
52                 join = new JoinRemote(ea_endpoint->ep_serial, remote, admin->sock);
53         }
54         else
55                 join = new JoinPBX(ea_endpoint);
56         if (!join)
57                 FATAL("No memoy for Join instance.\n");
58         ea_endpoint->ep_join_id = join->j_serial;
59         return(1);
60 }
61 void EndpointAppPBX::action_init_call(void)
62 {
63         _action_init_call(NULL);
64 }
65 void EndpointAppPBX::action_init_remote(void)
66 {
67 }
68
69 /*
70  * process dialing 'internal'
71  */
72 void EndpointAppPBX::action_dialing_internal(void)
73 {
74         struct capa_info        capainfo;
75         struct caller_info      callerinfo;
76         struct redir_info       redirinfo;
77         struct rtp_info         rtpinfo;
78         struct dialing_info     dialinginfo;
79         struct port_list        *portlist = ea_endpoint->ep_portlist;
80         struct lcr_msg          *message;
81         struct extension        ext;
82         struct route_param      *rparam;
83
84         /* send proceeding, because number is complete */
85         set_tone(portlist, "proceeding");
86         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
87         message_put(message);
88         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
89         new_state(EPOINT_STATE_IN_PROCEEDING);
90
91         /* create bearer/caller/dialinginfo */
92         memcpy(&capainfo, &e_capainfo, sizeof(capainfo));
93         memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo));
94         memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo));
95         memcpy(&rtpinfo, &e_rtpinfo, sizeof(rtpinfo));
96         memset(&dialinginfo, 0, sizeof(dialinginfo));
97         dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
98         SCPY(dialinginfo.id, e_dialinginfo.id);
99
100         /* process extension */
101         if ((rparam = routeparam(e_action, PARAM_EXTENSION)))
102                 SCPY(dialinginfo.id, rparam->string_value);
103
104         /* process number type */
105         if ((rparam = routeparam(e_action, PARAM_TYPE)))
106                 dialinginfo.ntype = rparam->integer_value;
107
108         /* process service */
109         if ((rparam = routeparam(e_action, PARAM_CAPA))) {
110                 capainfo.bearer_capa = rparam->integer_value;
111                 if (capainfo.bearer_capa != INFO_BC_SPEECH
112                  && capainfo.bearer_capa != INFO_BC_AUDIO) {
113                         capainfo.bearer_mode = INFO_BMODE_PACKET;
114                 }
115                 capainfo.bearer_info1 = INFO_INFO1_NONE;
116                 capainfo.hlc = INFO_HLC_NONE;
117                 capainfo.exthlc = INFO_HLC_NONE;
118         }
119         if ((rparam = routeparam(e_action, PARAM_BMODE))) {
120                 capainfo.bearer_mode = rparam->integer_value;
121         }
122         if ((rparam = routeparam(e_action, PARAM_INFO1))) {
123                 capainfo.bearer_info1 = rparam->integer_value;
124         }
125         if ((rparam = routeparam(e_action, PARAM_HLC))) {
126                 capainfo.hlc = rparam->integer_value;
127         }
128         if ((rparam = routeparam(e_action, PARAM_EXTHLC))) {
129                 capainfo.exthlc = rparam->integer_value;
130         }
131
132         /* process presentation */
133         if ((rparam = routeparam(e_action, PARAM_PRESENT))) {
134                 callerinfo.present = (rparam->integer_value)?INFO_PRESENT_ALLOWED:INFO_PRESENT_RESTRICTED;
135         }
136
137         /* check if extension exists AND only if not multiple extensions */
138         if (!strchr(dialinginfo.id,',') && !read_extension(&ext, dialinginfo.id)) {
139                 trace_header("ACTION extension (extension doesn't exist)", DIRECTION_NONE);
140                 add_trace("extension", NULL, dialinginfo.id);
141                 end_trace();
142                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0);
143                 new_state(EPOINT_STATE_OUT_DISCONNECT);
144                 message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
145                 set_tone(portlist, "cause_86");
146                 return;
147         }
148         /* check if internal calls are denied */
149         if (e_ext.rights < 1) {
150                 trace_header("ACTION extension (dialing to extension denied)", DIRECTION_NONE);
151                 add_trace("extension", NULL, dialinginfo.id);
152                 end_trace();
153                 new_state(EPOINT_STATE_OUT_DISCONNECT);
154                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0);
155                 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
156                 set_tone(portlist, "cause_81");
157                 return;
158         }
159
160         /* add or update internal call */
161         trace_header("ACTION extension (calling)", DIRECTION_NONE);
162         add_trace("extension", NULL, dialinginfo.id);
163         end_trace();
164         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
165         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
166         memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
167         memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
168         memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info));
169         memcpy(&message->param.setup.rtpinfo, &rtpinfo, sizeof(struct rtp_info));
170         message_put(message);
171 }
172
173 /* process dialing external
174  */
175 void EndpointAppPBX::action_dialing_external(void)
176 {
177         struct capa_info capainfo;
178         struct caller_info callerinfo;
179         struct redir_info redirinfo;
180         struct rtp_info rtpinfo;
181         struct dialing_info dialinginfo;
182         char *p;
183         struct port_list *portlist = ea_endpoint->ep_portlist;
184         struct lcr_msg *message;
185         struct route_param *rparam;
186
187         /* special processing of delete characters '*' and '#' */
188         if (e_ext.delete_ext) {
189                 /* dialing a # causes a clearing of complete number */
190                 if (strchr(e_extdialing, '#')) {
191                         e_extdialing[0] = '\0';
192                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): '#' detected: terminal '%s' selected caller id '%s' and continues dialing: '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, e_extdialing);
193                 }
194                 /* eliminate digits before '*', which is a delete digit
195                  */
196                 if (strchr(e_extdialing, '*')) {
197                         /* remove digits */
198                         while((p=strchr(e_extdialing, '*'))) {
199                                 if (p > e_extdialing) { /* only if there is a digit in front */
200                                         UCPY(p-1, p);
201                                         p--;
202                                 }
203                                 UCPY(p, p+1); /* remove '*' */
204                         }
205                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s deleted digits and got new string: %s\n", ea_endpoint->ep_serial, e_ext.number, e_extdialing);
206                 }
207         }
208
209         /* create bearer/caller/dialinginfo */
210         memcpy(&capainfo, &e_capainfo, sizeof(capainfo));
211         memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo));
212         memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo));
213         memcpy(&rtpinfo, &e_rtpinfo, sizeof(rtpinfo));
214         memset(&dialinginfo, 0, sizeof(dialinginfo));
215         dialinginfo.itype = INFO_ITYPE_ISDN;
216 //      dialinginfo.sending_complete = 0;
217         SCPY(dialinginfo.id, e_extdialing);
218
219         /* process prefix */
220         if ((rparam = routeparam(e_action, PARAM_PREFIX)))
221                 SPRINT(dialinginfo.id, "%s%s", rparam->string_value, e_extdialing);
222
223         /* process keypad */
224         if ((rparam = routeparam(e_action, PARAM_KEYPAD))) {
225                 SCPY(dialinginfo.keypad, dialinginfo.id);
226                 dialinginfo.id[0] = '\0';
227         }
228
229         /* process number complete */
230         if ((rparam = routeparam(e_action, PARAM_COMPLETE)))
231                 dialinginfo.sending_complete = 1;
232
233         /* process number type */
234         if ((rparam = routeparam(e_action, PARAM_TYPE)))
235                 dialinginfo.ntype = rparam->integer_value;
236
237         /* process service */
238         if ((rparam = routeparam(e_action, PARAM_CAPA))) {
239                 capainfo.bearer_capa = rparam->integer_value;
240                 if (capainfo.bearer_capa != INFO_BC_SPEECH
241                  && capainfo.bearer_capa != INFO_BC_AUDIO) {
242                         capainfo.bearer_mode = INFO_BMODE_PACKET;
243                 }
244                 capainfo.bearer_info1 = INFO_INFO1_NONE;
245                 capainfo.hlc = INFO_HLC_NONE;
246                 capainfo.exthlc = INFO_HLC_NONE;
247         }
248         if ((rparam = routeparam(e_action, PARAM_BMODE))) {
249                 capainfo.bearer_mode = rparam->integer_value;
250         }
251         if ((rparam = routeparam(e_action, PARAM_INFO1))) {
252                 capainfo.bearer_info1 = rparam->integer_value;
253         }
254         if ((rparam = routeparam(e_action, PARAM_HLC))) {
255                 capainfo.hlc = rparam->integer_value;
256         }
257         if ((rparam = routeparam(e_action, PARAM_EXTHLC))) {
258                 capainfo.exthlc = rparam->integer_value;
259         }
260
261
262         /* process callerid */
263         if ((rparam = routeparam(e_action, PARAM_CALLERID))) {
264                 SCPY(callerinfo.id, rparam->string_value);
265         }
266         if ((rparam = routeparam(e_action, PARAM_CALLERIDTYPE))) {
267                 callerinfo.ntype = rparam->integer_value;
268         }
269
270         /* process presentation */
271         if ((rparam = routeparam(e_action, PARAM_PRESENT))) {
272                 callerinfo.present = (rparam->integer_value)?INFO_PRESENT_ALLOWED:INFO_PRESENT_RESTRICTED;
273         }
274
275         /* process interfaces */
276         if ((rparam = routeparam(e_action, PARAM_INTERFACES)))
277                 SCPY(dialinginfo.interfaces, rparam->string_value);
278
279         /* check if local calls are denied */
280         if (e_ext.rights < 2) {
281                 trace_header("ACTION extern (calling denied)", DIRECTION_NONE);
282                 end_trace();
283                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0);
284                 set_tone(portlist, "cause_82");
285                 denied:
286                 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
287                 new_state(EPOINT_STATE_OUT_DISCONNECT);
288                 return;
289         }
290
291         if (!strncmp(dialinginfo.id, options.national, strlen(options.national))
292          || dialinginfo.ntype == INFO_NTYPE_NATIONAL
293          || dialinginfo.ntype == INFO_NTYPE_INTERNATIONAL) {
294                 /* check if national calls are denied */
295                 if (e_ext.rights < 3) {
296                         trace_header("ACTION extern (national calls denied)", DIRECTION_NONE);
297                         end_trace();
298                         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0);
299                         set_tone(portlist, "cause_83");
300                         goto denied;
301                 }
302         }
303
304         if (!strncmp(dialinginfo.id, options.international, strlen(options.international))
305          || dialinginfo.ntype == INFO_NTYPE_INTERNATIONAL) {
306                 /* check if international calls are denied */
307                 if (e_ext.rights < 4) {
308                         trace_header("ACTION extern (international calls denied)", DIRECTION_NONE);
309                         end_trace();
310                         release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0);
311                         set_tone(portlist, "cause_84");
312                         goto denied;
313                 }
314         }
315
316         /* add or update outgoing call */
317         trace_header("ACTION extern (calling)", DIRECTION_NONE);
318         add_trace("number", NULL, dialinginfo.id);
319         if (dialinginfo.sending_complete)
320         add_trace("number", "complete", "yes");
321         if (dialinginfo.interfaces[0])
322                 add_trace("interfaces", NULL, dialinginfo.interfaces);
323         end_trace();
324         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
325         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
326         memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
327         memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
328         memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info));
329         memcpy(&message->param.setup.rtpinfo, &rtpinfo, sizeof(struct rtp_info));
330         message_put(message);
331 }
332
333
334 void EndpointAppPBX::action_dialing_remote(void)
335 {
336         struct route_param      *rparam;
337         struct port_list        *portlist = ea_endpoint->ep_portlist;
338         struct lcr_msg          *message;
339         struct capa_info        capainfo;
340         struct caller_info      callerinfo;
341         struct redir_info       redirinfo;
342         struct dialing_info     dialinginfo;
343         char                    context[128] = "";
344         char                    remote[32];
345
346         if (!ea_endpoint->ep_join_id) {
347                 /* no join yet, sending setup */
348                 if (!(rparam = routeparam(e_action, PARAM_APPLICATION))) {
349                         trace_header("ACTION remote (no application given)", DIRECTION_NONE);
350                         end_trace();
351                         new_state(EPOINT_STATE_OUT_DISCONNECT);
352                         message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
353                         set_tone(portlist, "cause_3f");
354                         return;
355                 }
356                 SCPY(remote, rparam->string_value);
357                 if (!_action_init_call(remote))
358                         return;
359
360                 /* create bearer/caller/dialinginfo */
361                 memcpy(&capainfo, &e_capainfo, sizeof(capainfo));
362                 memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo));
363                 memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo));
364                 memset(&dialinginfo, 0, sizeof(dialinginfo));
365
366                 if ((rparam = routeparam(e_action, PARAM_CONTEXT))) {
367                         SCPY(context, rparam->string_value);
368                 }
369                 if ((rparam = routeparam(e_action, PARAM_EXTEN))) {
370                         SCPY(dialinginfo.id, rparam->string_value);
371                         dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
372                 } else {
373                         SCPY(dialinginfo.id, e_extdialing);
374                 }
375                 e_extdialing = e_dialinginfo.id + strlen(e_dialinginfo.id);
376                 /* send setup to remote */
377                 trace_header("ACTION remote (setup)", DIRECTION_NONE);
378                 add_trace("number", NULL, dialinginfo.id);
379                 add_trace("remote", NULL, remote);
380                 if (context[0])
381                         add_trace("context", NULL, context);
382                 end_trace();
383                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
384                 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
385                 memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
386                 memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
387                 memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info));
388                 SCPY(message->param.setup.context, context);
389                 message_put(message);
390         } else {
391                 /* send overlap digits */
392                 trace_header("ACTION remote (dialing)", DIRECTION_NONE);
393                 add_trace("number", NULL, e_extdialing);
394                 end_trace();
395                 if (e_extdialing[0]) {
396                         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_INFORMATION);
397                         memcpy(&message->param.information, &e_dialinginfo, sizeof(struct dialing_info));
398                         SCPY(message->param.information.id, e_extdialing);
399                         e_extdialing = e_dialinginfo.id + strlen(e_dialinginfo.id);
400                         message_put(message);
401                 }
402         }
403 }
404
405
406 /*
407  * process dialing the "am" and record
408  */
409 void EndpointAppPBX::action_dialing_vbox_record(void)
410 {
411         struct dialing_info dialinginfo;
412         struct port_list *portlist = ea_endpoint->ep_portlist;
413         struct lcr_msg *message;
414         struct extension ext;
415         struct route_param *rparam;
416
417         portlist = ea_endpoint->ep_portlist;
418
419         /* check for given extension */
420         if (!(rparam = routeparam(e_action, PARAM_EXTENSION))) {
421                 trace_header("ACTION vbox-record (no extension given by parameter)", DIRECTION_NONE);
422                 end_trace();
423
424                 new_state(EPOINT_STATE_OUT_DISCONNECT);
425                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
426                 set_tone(portlist, "cause_3f");
427                 return;
428         }
429
430         /* check if extension exists */
431         if (!read_extension(&ext, rparam->string_value)) {
432                 trace_header("ACTION vbox-record (given extension does not exists)", DIRECTION_NONE);
433                 add_trace("extension", NULL, "%s", rparam->string_value);
434                 end_trace();
435                 new_state(EPOINT_STATE_OUT_DISCONNECT);
436                 message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
437                 set_tone(portlist, "cause_86");
438                 return;
439         }
440
441         /* check if internal calls are denied */
442         if (e_ext.rights < 1) {
443                 trace_header("ACTION vbox-record (internal calls are denied)", DIRECTION_NONE);
444                 end_trace();
445                 new_state(EPOINT_STATE_OUT_DISCONNECT);
446                 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
447                 set_tone(portlist, "cause_81");
448                 return;
449         }
450
451         set_tone(portlist, "proceeding");
452         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
453         message_put(message);
454         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
455         new_state(EPOINT_STATE_IN_PROCEEDING);
456
457         memset(&dialinginfo, 0, sizeof(dialinginfo));
458         dialinginfo.itype = INFO_ITYPE_VBOX;
459         dialinginfo.sending_complete = 1;
460         SCPY(dialinginfo.id, rparam->string_value);
461
462         /* append special announcement (if given) */
463         if ((rparam = routeparam(e_action, PARAM_ANNOUNCEMENT)))
464         if (rparam->string_value[0]) {
465                 SCAT(dialinginfo.id, ",");
466                 SCAT(dialinginfo.id, rparam->string_value);
467         }
468
469         /* add or update internal call */
470         trace_header("ACTION vbox-record (calling)", DIRECTION_NONE);
471         add_trace("extension", NULL, "%s", dialinginfo.id);
472         end_trace();
473         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
474         memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
475         memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
476         memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
477         memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
478         message_put(message);
479 }
480
481
482 /*
483  * process partyline
484  */
485 void EndpointAppPBX::action_init_partyline(void)
486 {
487         class Join *join;
488         class JoinPBX *joinpbx;
489         struct port_list *portlist = ea_endpoint->ep_portlist;
490         struct lcr_msg *message;
491         struct route_param *rparam;
492         int partyline, jingle = 0;
493         struct join_relation *relation;
494
495         portlist = ea_endpoint->ep_portlist;
496
497         /* check for given extension */
498         if (!(rparam = routeparam(e_action, PARAM_ROOM))) {
499                 trace_header("ACTION partyline (no room parameter)", DIRECTION_NONE);
500                 end_trace();
501                 noroom:
502                 new_state(EPOINT_STATE_OUT_DISCONNECT);
503                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
504                 set_tone(portlist, "cause_3f");
505                 return;
506         }
507         if (rparam->integer_value <= 0) {
508                 trace_header("ACTION partyline (illegal room parameter)", DIRECTION_NONE);
509                 add_trace("room", NULL, "%d", rparam->integer_value);
510                 end_trace();
511                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): invalid value for 'room'.\n", ea_endpoint->ep_serial);
512                 goto noroom;
513         }
514         partyline = rparam->integer_value;
515         if ((rparam = routeparam(e_action, PARAM_JINGLE)))
516                 jingle = 1;
517
518         /* don't create join if partyline exists */
519         join = join_first;
520         while(join) {
521                 if (join->j_type == JOIN_TYPE_PBX) {
522                         joinpbx = (class JoinPBX *)join;
523                         if (joinpbx->j_partyline == partyline)
524                                 break;
525                 }
526                 join = join->next;
527         }
528         if (!join) {
529                 /* create join */
530                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new join instance.\n", ea_endpoint->ep_serial);
531                 if (!(join = new JoinPBX(ea_endpoint)))
532                         FATAL("No memory for join object\n");
533         } else {
534 //NOTE: joinpbx must be set here
535                 /* add relation to existing join */
536                 if (!(relation=joinpbx->add_relation()))
537                         FATAL("No memory for join relation\n");
538                 relation->type = RELATION_TYPE_SETUP;
539                 relation->channel_state = 1;
540                 relation->rx_state = NOTIFY_STATE_ACTIVE;
541                 relation->tx_state = NOTIFY_STATE_ACTIVE;
542                 relation->epoint_id = ea_endpoint->ep_serial;
543
544         }
545         ea_endpoint->ep_join_id = join->j_serial;
546
547         set_tone(portlist, "proceeding");
548         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
549         message_put(message);
550         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
551         new_state(EPOINT_STATE_IN_PROCEEDING);
552
553         /* send setup to join */
554         trace_header("ACTION partyline (calling)", DIRECTION_NONE);
555         add_trace("room", NULL, "%d", partyline);
556         add_trace("jingle", NULL, (jingle)?"on":"off");
557         end_trace();
558         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
559         message->param.setup.partyline = partyline;
560         message->param.setup.partyline_jingle = jingle;
561         memcpy(&message->param.setup.dialinginfo, &e_dialinginfo, sizeof(struct dialing_info));
562         memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
563         memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
564         memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
565         message_put(message);
566 }
567
568
569 /*
570  * process hangup of all calls
571  */
572 void EndpointAppPBX::action_hangup_call(void)
573 {
574         trace_header("ACTION hangup", DIRECTION_NONE);
575         end_trace();
576 }
577
578
579 /*
580  * process dialing 'login'
581  */
582 void EndpointAppPBX::action_dialing_login(void)
583 {
584         struct port_list *portlist = ea_endpoint->ep_portlist;
585         struct lcr_msg *message;
586         char *extension;
587         struct route_param *rparam;
588
589         /* extension parameter */
590         if ((rparam = routeparam(e_action, PARAM_EXTENSION))) {
591                 /* extension is given by parameter */
592                 extension = rparam->string_value;
593                 if (extension[0] == '\0')
594                         return;
595                 if (!read_extension(&e_ext, extension)) {
596                         trace_header("ACTION login (extension doesn't exist)", DIRECTION_NONE);
597                         add_trace("extension", NULL, "%s", extension);
598                         end_trace();
599                         /* extension doesn't exist */
600                         new_state(EPOINT_STATE_OUT_DISCONNECT);
601                         message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
602                         set_tone(portlist, "cause_86");
603                         return;
604                 }
605         } else {
606                 /* extension must be given by dialstring */
607                 extension = e_extdialing;
608                 if (extension[0] == '\0')
609                         return;
610                 if (!read_extension(&e_ext, extension)) {
611                         trace_header("ACTION login (extension incomplete or does not exist)", DIRECTION_NONE);
612                         add_trace("extension", NULL, "%s", extension);
613                         end_trace();
614                         return;
615                 }
616         }
617
618         /* we changed our extension */
619         SCPY(e_ext.number, extension);
620         new_state(EPOINT_STATE_CONNECT);
621         e_dtmf = 1;
622         e_connectedmode = 1;
623
624         /* send connect with extension's caller id (COLP) */
625         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
626         SCPY(message->param.connectinfo.id, e_ext.callerid);
627         message->param.connectinfo.ntype = e_ext.callerid_type;
628         if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
629                 message->param.connectinfo.present = INFO_PRESENT_RESTRICTED;
630         else    message->param.connectinfo.present = e_ext.callerid_present;
631         /* handle restricted caller ids */
632         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);
633         /* display callerid if desired for extension */
634         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));
635         message->param.connectinfo.ntype = e_ext.callerid_type;
636         message_put(message);
637         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
638
639         /* set our caller id */
640         SCPY(e_callerinfo.id, e_ext.callerid);
641         e_callerinfo.ntype = e_ext.callerid_type;
642         e_callerinfo.present = e_ext.callerid_present;
643
644         /* enable connectedmode */
645         e_connectedmode = 1;
646         e_dtmf = 1;
647
648         if (!(rparam = routeparam(e_action, PARAM_NOPASSWORD))) {
649                 /* make call state to enter password */
650                 trace_header("ACTION login (ask for password)", DIRECTION_NONE);
651                 add_trace("extension", NULL, "%s", e_ext.number);
652                 end_trace();
653                 new_state(EPOINT_STATE_IN_OVERLAP);
654                 e_ruleset = NULL;
655                 e_rule = NULL;
656                 e_action = &action_password;
657                 unsched_timer(&e_match_timeout);
658                 e_match_to_action = NULL;
659                 e_dialinginfo.id[0] = '\0';
660                 e_extdialing = strchr(e_dialinginfo.id, '\0');
661
662                 /* set timeout */
663                 schedule_timer(&e_password_timeout, 20, 0);
664
665                 /* do dialing */
666                 process_dialing(0);
667         } else {
668                 /* make call state  */
669                 new_state(EPOINT_STATE_IN_OVERLAP);
670                 e_ruleset = ruleset_main;
671                 if (e_ruleset)
672                         e_rule = e_ruleset->rule_first;
673                 e_action = NULL;
674                 e_dialinginfo.id[0] = '\0';
675                 e_extdialing = e_dialinginfo.id;
676                 set_tone(portlist, "dialpbx");
677         }
678 }
679
680
681 /*
682  * process init 'change_callerid'
683  */
684 void EndpointAppPBX::action_init_change_callerid(void)
685 {
686         struct port_list *portlist = ea_endpoint->ep_portlist;
687
688         if (!e_ext.change_callerid) {
689                 /* service not available */
690                 trace_header("ACTION change-callerid (denied for this caller)", DIRECTION_NONE);
691                 end_trace();
692                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
693                 new_state(EPOINT_STATE_OUT_DISCONNECT);
694                 set_tone(portlist,"cause_87");
695                 return;
696         }
697 }
698
699 /* process dialing callerid
700  */
701 void EndpointAppPBX::_action_callerid_calleridnext(int next)
702 {
703         struct port_list *portlist = ea_endpoint->ep_portlist;
704         struct route_param *rparam;
705         char buffer[64], *callerid;
706         char old_id[64] = "", new_id[64] = "";
707         int old_type=0, new_type=0, old_present=0, new_present=0;
708
709         if ((rparam = routeparam(e_action, PARAM_CALLERID))) {
710                 /* the caller ID is given by parameter */
711                 callerid = rparam->string_value;
712         } else {
713                 /* caller ID is dialed */
714                 if (!strchr(e_extdialing, '#')) {
715                         /* no complete ID yet */
716                         return;
717                 }
718                 *strchr(e_extdialing, '#') = '\0';
719                 callerid = e_extdialing;
720         }
721
722         /* given callerid type */
723         if ((rparam = routeparam(e_action, PARAM_CALLERIDTYPE)))
724                 switch(rparam->integer_value) {
725                         case INFO_NTYPE_SUBSCRIBER:
726                         SPRINT(buffer, "s%s", callerid);
727                         callerid = buffer;
728                         break;
729                         case INFO_NTYPE_NATIONAL:
730                         SPRINT(buffer, "n%s", callerid);
731                         callerid = buffer;
732                         break;
733                         case INFO_NTYPE_INTERNATIONAL:
734                         SPRINT(buffer, "i%s", callerid);
735                         callerid = buffer;
736                         break;
737                         default:
738                         SPRINT(buffer, "%s", callerid);
739                         callerid = buffer;
740                         break;
741                 }
742
743         /* caller id complete, dialing with new caller id */
744         /* write new parameters */
745         if (read_extension(&e_ext, e_ext.number)) {
746                 old_present = (!next)?e_ext.callerid_present:e_ext.id_next_call_present;
747                 old_type = (!next)?e_ext.callerid_type:e_ext.id_next_call_type;
748                 SCPY(old_id, (!next)?e_ext.callerid:e_ext.id_next_call);
749                 if (callerid[0] == '\0') {
750                         /* no caller id */
751                         (!next)?e_ext.callerid_present:e_ext.id_next_call_present = INFO_PRESENT_RESTRICTED;
752                 } else {
753                         /* new caller id */
754                         (!next)?e_ext.callerid_present:e_ext.id_next_call_present = INFO_PRESENT_ALLOWED;
755                         if ((rparam = routeparam(e_action, PARAM_PRESENT))) if (rparam->integer_value == 0)
756                                 (!next)?e_ext.callerid_present:e_ext.id_next_call_present = INFO_PRESENT_RESTRICTED;
757                         if (e_ext.callerid_type == INFO_NTYPE_UNKNOWN) /* if callerid is unknown, the given id is not nationalized */ {
758                                 SCPY((!next)?e_ext.callerid:e_ext.id_next_call, callerid);
759                                 (!next)?e_ext.callerid_type:e_ext.id_next_call_type = INFO_NTYPE_UNKNOWN;
760                         } else {
761                                 SCPY((!next)?e_ext.callerid:e_ext.id_next_call, nationalize_callerinfo(callerid,&((!next)?e_ext.callerid_type:e_ext.id_next_call_type), options.national, options.international));
762                         }
763                         if (!next) e_ext.id_next_call_type = -1;
764                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): nationalized callerid: '%s' type=%d\n", ea_endpoint->ep_serial, (!next)?e_ext.callerid:e_ext.id_next_call, (!next)?e_ext.callerid_type:e_ext.id_next_call_type);
765                 }
766                 new_present = (!next)?e_ext.callerid_present:e_ext.id_next_call_present;
767                 new_type = (!next)?e_ext.callerid_type:e_ext.id_next_call_type;
768                 SCPY(new_id, (!next)?e_ext.callerid:e_ext.id_next_call);
769                 write_extension(&e_ext, e_ext.number);
770         }
771
772         /* function activated */
773         if (next)
774                 trace_header("ACTION change-callerid (only next call)", DIRECTION_NONE);
775         else
776                 trace_header("ACTION change-callerid (all future calls)", DIRECTION_NONE);
777         add_trace("old", "caller id", "%s", numberrize_callerinfo(old_id, old_type, options.national, options.international));
778         add_trace("old", "present", "%s", (old_present==INFO_PRESENT_RESTRICTED)?"restricted":"allowed");
779         add_trace("new", "caller id", "%s", numberrize_callerinfo(new_id, new_type, options.national, options.international));
780         add_trace("new", "present", "%s", (new_present==INFO_PRESENT_RESTRICTED)?"restricted":"allowed");
781         end_trace();
782         message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
783         new_state(EPOINT_STATE_OUT_DISCONNECT);
784         set_tone(portlist,"activated");
785 }
786
787 /* process dialing callerid for all call
788  */
789 void EndpointAppPBX::action_dialing_callerid(void)
790 {
791         _action_callerid_calleridnext(0);
792 }
793
794 /* process dialing callerid for next call
795  */
796 void EndpointAppPBX::action_dialing_calleridnext(void)
797 {
798         _action_callerid_calleridnext(1);
799 }
800
801
802 /*
803  * process init 'change_forward'
804  */
805 void EndpointAppPBX::action_init_change_forward(void)
806 {
807         struct port_list *portlist = ea_endpoint->ep_portlist;
808
809         if (!e_ext.change_forward) {
810                 trace_header("ACTION change-forward (denied for this caller)", DIRECTION_NONE);
811                 end_trace();
812                 /* service not available */             
813                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
814                 new_state(EPOINT_STATE_OUT_DISCONNECT);
815                 set_tone(portlist,"cause_87");
816                 return;
817         }
818 }
819
820 /* process dialing forwarding
821  */
822 void EndpointAppPBX::action_dialing_forward(void)
823 {
824         struct port_list *portlist = ea_endpoint->ep_portlist;
825         int diversion = INFO_DIVERSION_CFU;
826         char *dest = e_extdialing;
827         struct route_param *rparam;
828
829         /* if diversion type is given */
830         if ((rparam = routeparam(e_action, PARAM_DIVERSION)))
831                 diversion = rparam->integer_value;
832
833         if ((rparam = routeparam(e_action, PARAM_DEST))) {
834                 /* if destination is given */
835                 dest = rparam->string_value;
836         } else {
837                 if (!strchr(e_extdialing, '#'))
838                         return;
839                 *strchr(e_extdialing, '#') = '\0';
840                 dest = e_extdialing;
841         }
842
843         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing forwarding to '%s'.\n", ea_endpoint->ep_serial, e_ext.number, dest);
844         if (read_extension(&e_ext, e_ext.number)) {
845                 switch(diversion) {
846                         case INFO_DIVERSION_CFU:
847                         trace_header("ACTION change-forward (new CFU=unconditional)", DIRECTION_NONE);
848                         add_trace("destin'", NULL, "%s", dest);
849                         end_trace();
850                         SCPY(e_ext.cfu, dest);
851                         break;
852                         case INFO_DIVERSION_CFB:
853                         trace_header("ACTION change-forward (new CFB=busy)", DIRECTION_NONE);
854                         add_trace("destin'", NULL, "%s", dest);
855                         end_trace();
856                         SCPY(e_ext.cfb, dest);
857                         break;
858                         case INFO_DIVERSION_CFNR:
859                         if ((rparam = routeparam(e_action, PARAM_DELAY)))
860                                 e_ext.cfnr_delay = rparam->integer_value;
861                         trace_header("ACTION change-forward (new CFNR=no response)", DIRECTION_NONE);
862                         add_trace("destin'", NULL, "%s", dest);
863                         add_trace("delay", NULL, "%s", e_ext.cfnr_delay);
864                         end_trace();
865                         SCPY(e_ext.cfnr, dest);
866                         break;
867                         case INFO_DIVERSION_CFP:
868                         trace_header("ACTION change-forward (new CFP=parallel)", DIRECTION_NONE);
869                         add_trace("destin'", NULL, "%s", dest);
870                         end_trace();
871                         SCPY(e_ext.cfp, dest);
872                         break;
873                 }
874                 write_extension(&e_ext, e_ext.number);
875         }
876         /* function (de)activated */
877         message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
878         new_state(EPOINT_STATE_OUT_DISCONNECT);
879         if (dest[0])
880                 set_tone(portlist,"activated");
881         else
882                 set_tone(portlist,"deactivated");
883 }
884
885
886 /* process dialing redial
887 */
888 void EndpointAppPBX::action_init_redial_reply(void)
889 {
890         struct port_list *portlist = ea_endpoint->ep_portlist;
891
892         e_select = 0;
893         if (!e_ext.last_out[0]) {
894                 trace_header("ACTION redial/reply (no last number stored)", DIRECTION_NONE);
895                 end_trace();
896                 new_state(EPOINT_STATE_OUT_DISCONNECT);
897                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
898                 set_tone(portlist, "cause_3f");
899                 return;
900         }
901 }
902
903 /* process dialing redial
904 */
905 void EndpointAppPBX::_action_redial_reply(int in)
906 {
907         struct lcr_msg *message;
908         char *last;
909         struct route_param *rparam;
910
911         last = (in)?e_ext.last_in[0]:e_ext.last_out[0];
912
913         /* if no display is available */
914         if (!e_ext.display_menu)
915                 goto nodisplay;
916         if (ea_endpoint->ep_portlist->port_type!=PORT_TYPE_DSS1_NT_IN && ea_endpoint->ep_portlist->port_type!=PORT_TYPE_DSS1_NT_OUT)
917                 goto nodisplay;
918
919         /* if select is not given */
920         if (!(rparam = routeparam(e_action, PARAM_SELECT)))
921                 goto nodisplay;
922
923         /* scroll menu */
924         if (e_extdialing[0]=='*' || e_extdialing[0]=='1') {
925                 /* find prev entry */
926                 e_select--;
927                 if (e_select < 0)
928                         e_select = 0;
929
930         }
931         if (e_extdialing[0]=='#' || e_extdialing[0]=='3') {
932                 /* find next entry */
933                 e_select++;
934                 if (e_select >= MAX_REMEMBER) {
935                         e_select--;
936                 } else if (in) {
937                         if (e_ext.last_in[e_select][0] == '\0')
938                                 e_select--;
939                 } else
940                         if (e_ext.last_out[e_select][0] == '\0')
941                                 e_select--;
942
943         }
944
945         last = (in)?e_ext.last_in[e_select]:e_ext.last_out[e_select];
946         if (e_extdialing[0]=='0' || e_extdialing[0]=='2') {
947                 nodisplay:
948                 if (in)
949                         trace_header("ACTION reply (dialing)", DIRECTION_NONE);
950                 else
951                         trace_header("ACTION redial (dialing)", DIRECTION_NONE);
952                 add_trace("number", NULL, "%s", last);
953                 add_trace("last but", NULL, "%d", e_select);
954                 end_trace();
955                 SCPY(e_dialinginfo.id, last);
956                 e_extdialing = e_dialinginfo.id;
957                 e_action = NULL;
958                 process_dialing(0);
959                 return;
960         }
961         e_extdialing[0] = '\0';
962         
963         /* send display message to port */
964         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
965         if (!strncmp(last, "extern:", 7))
966                 SPRINT(message->param.notifyinfo.display, "(%d) %s ext", e_select+1, last+7);
967         else
968         if (!strncmp(last, "intern:", 7))
969                 SPRINT(message->param.notifyinfo.display, "(%d) %s int", e_select+1, last+7);
970         else
971         if (!strncmp(last, "chan:", 4))
972                 SPRINT(message->param.notifyinfo.display, "(%d) %s chan", e_select+1, last+5);
973         else
974         if (!strncmp(last, "vbox:", 5))
975                 SPRINT(message->param.notifyinfo.display, "(%d) %s vbox", e_select+1, last+5);
976         else
977                 SPRINT(message->param.notifyinfo.display, "(%d) %s", e_select+1, (last[0])?last:"- empty -");
978         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s sending display:%s\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
979         message_put(message);
980         logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
981 }
982
983 /* process dialing redial
984 */
985 void EndpointAppPBX::action_dialing_redial(void)
986 {
987         _action_redial_reply(0);
988 }
989
990 /* process dialing reply
991 */
992 void EndpointAppPBX::action_dialing_reply(void)
993 {
994         _action_redial_reply(1);
995 }
996
997
998 /* dialing powerdialing delay
999  */
1000 void EndpointAppPBX::action_dialing_powerdial(void)
1001 {
1002         struct port_list *portlist = ea_endpoint->ep_portlist;
1003         struct lcr_msg *message;
1004         struct route_param *rparam;
1005
1006         /* power dialing only possible if we have a last dialed number */
1007         if (!e_ext.last_out[0]) {
1008                 trace_header("ACTION powerdial (no last number stored)", DIRECTION_NONE);
1009                 end_trace();
1010                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1011                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1012                 set_tone(portlist, "cause_3f");
1013                 return;
1014         }
1015
1016         /* limit */
1017         if ((rparam = routeparam(e_action, PARAM_LIMIT))) {
1018                 e_powerlimit = rparam->integer_value;
1019         } else {
1020                 e_powerlimit = 0;
1021         }
1022
1023         /* delay */
1024         if ((rparam = routeparam(e_action, PARAM_DELAY))) {
1025                 e_powerdelay = rparam->integer_value;
1026         } else {
1027                 /* delay incomplete */
1028                 if (!strchr(e_extdialing, '#'))
1029                         return;
1030                 *strchr(e_extdialing, '#') = '\0';
1031                 e_powerdelay = e_extdialing[0]?atoi(e_extdialing): 0;
1032         }
1033
1034         if (e_powerdelay < 1)
1035                 e_powerdelay = 0.2;
1036         trace_header("ACTION powerdial (dialing)", DIRECTION_NONE);
1037         add_trace("number", NULL, "%s", e_ext.last_out[0]);
1038         add_trace("delay", NULL, "%d", e_powerdelay);
1039         end_trace();
1040
1041         /* send connect to avoid overlap timeout */
1042 //      new_state(EPOINT_STATE_CONNECT); connect may prevent further dialing
1043         if (e_ext.number[0])
1044                 e_dtmf = 1;
1045         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1046         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1047         message_put(message);
1048         logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1049
1050         /* do dialing */
1051         SCPY(e_dialinginfo.id, e_ext.last_out[0]);
1052         e_powerdial_on = 1; /* indicates the existence of powerdialing but no redial time given */
1053         e_powercount = 0;
1054         e_action = NULL;
1055         process_dialing(0);
1056 }
1057
1058
1059 /* dialing callback
1060  */
1061 void EndpointAppPBX::action_dialing_callback(void)
1062 {
1063         struct port_list *portlist = ea_endpoint->ep_portlist;
1064         struct route_param *rparam;
1065         struct extension cbext;
1066
1067         portlist = ea_endpoint->ep_portlist;
1068
1069         /* check given extension */
1070         if (!(rparam = routeparam(e_action, PARAM_EXTENSION))) {
1071                 noextension:
1072                 trace_header("ACTION callback (no extension defined)", DIRECTION_NONE);
1073                 end_trace();
1074                 disconnect:
1075
1076                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1077                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1078                 set_tone(portlist, "cause_3f");
1079                 e_action = NULL;
1080                 e_cbcaller[0] = e_cbdialing[0] = '\0';
1081                 return;
1082         }
1083
1084         /* if extension is given */
1085         SCPY(e_cbcaller, rparam->string_value);
1086         if (e_cbcaller[0] == '\0')
1087                 goto noextension;
1088
1089         /* read callback extension */
1090         memset(&cbext, 0, sizeof(cbext));
1091         if (!read_extension(&cbext, e_cbcaller)) {
1092                 trace_header("ACTION callback (extension doesn't exist)", DIRECTION_NONE);
1093                 add_trace("extension", NULL, "%s", e_cbcaller);
1094                 end_trace();
1095                 goto disconnect;
1096         }
1097
1098         /* if password is not given */
1099         if (cbext.password[0] == '\0') {
1100                 trace_header("ACTION callback (no password set)", DIRECTION_NONE);
1101                 add_trace("extension", NULL, "%s", e_cbcaller);
1102                 end_trace();
1103                 goto disconnect;
1104         }
1105
1106         /* callback only possible if callerid exists OR it is given */
1107         if ((rparam = routeparam(e_action, PARAM_CALLTO)))
1108                 SCPY(e_cbto, rparam->string_value);
1109         if (e_cbto[0]) {
1110                 trace_header("ACTION callback (alternative caller id)", DIRECTION_NONE);
1111                 add_trace("extension", NULL, "%s", e_cbcaller);
1112                 add_trace("callerid", NULL, "%s", e_cbto);
1113                 end_trace();
1114                 SCPY(e_callerinfo.id, e_cbto);
1115                 e_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1116                 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1117         }
1118         if (e_callerinfo.id[0]=='\0' || e_callerinfo.present==INFO_PRESENT_NOTAVAIL) {
1119                 trace_header("ACTION callback (no caller ID available)", DIRECTION_NONE);
1120                 add_trace("extension", NULL, "%s", e_cbcaller);
1121                 end_trace();
1122                 goto disconnect;
1123         }
1124         /* present id */
1125         e_callerinfo.present = INFO_PRESENT_ALLOWED;
1126
1127 }
1128
1129 /*
1130  * process hangup 'callback'
1131  */
1132 void EndpointAppPBX::action_hangup_callback(void)
1133 {
1134         struct route_param *rparam;
1135         int delay;
1136
1137         /* set delay */
1138         delay = 2; /* default value */
1139         if ((rparam = routeparam(e_action, PARAM_DELAY)))
1140         if (rparam->integer_value>0)
1141                 delay = rparam->integer_value;
1142
1143         /* dialing after callback */
1144         if ((rparam = routeparam(e_action, PARAM_PREFIX)))
1145                 SCPY(e_cbdialing, rparam->string_value);
1146         else
1147                 SCPY(e_cbdialing, e_extdialing);
1148
1149         trace_header("ACTION callback (dialing)", DIRECTION_NONE);
1150         add_trace("extension", NULL, "%s", e_cbcaller);
1151         add_trace("caller id", NULL, "%s", e_callerinfo.id);
1152         add_trace("delay", NULL, "%d", delay);
1153         add_trace("dialing", NULL, "%s", e_cbdialing);
1154         end_trace();
1155
1156         /* set time to callback */
1157         schedule_timer(&e_callback_timeout, delay, 0);
1158 }
1159
1160
1161 /*
1162  * dialing action abbreviation
1163  */
1164 void EndpointAppPBX::action_dialing_abbrev(void)
1165 {
1166         struct port_list *portlist = ea_endpoint->ep_portlist;
1167         char *abbrev, *phone, *name;
1168         int result;
1169
1170         portlist = ea_endpoint->ep_portlist;
1171
1172         /* abbrev dialing is only possible if we have a caller defined */
1173         if (!e_ext.number[0]) {
1174                 trace_header("ACTION abbreviation (only for extension)", DIRECTION_NONE);
1175                 end_trace();
1176                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1177                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1178                 set_tone(portlist, "cause_3f");
1179                 return;
1180         }
1181
1182         /* check abbreviation */
1183         abbrev = e_extdialing;
1184         phone = NULL;
1185         name = NULL;
1186         result = parse_phonebook(e_ext.number, &abbrev, &phone, &name);
1187         if (result == 0) {
1188                 trace_header("ACTION abbreviation (not found)", DIRECTION_NONE);
1189                 add_trace("abbrev", NULL, "%s", abbrev);
1190                 end_trace();
1191                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1192                 message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
1193                 set_tone(portlist, "cause_01");
1194                 return;
1195         }
1196         if (result == -1) { /* may match if more digits are dialed */
1197                 return;
1198         }
1199
1200         /* dial abbreviation */ 
1201         trace_header("ACTION abbreviation (dialing)", DIRECTION_NONE);
1202         add_trace("abbrev", NULL, "%s", abbrev);
1203         add_trace("number", NULL, "%s", phone);
1204         if (name) if (name[0])
1205                 add_trace("name", NULL, "%s", name);
1206         end_trace();
1207         SCPY(e_dialinginfo.id, phone);
1208         e_extdialing = e_dialinginfo.id;
1209         e_action = NULL;
1210         process_dialing(0);
1211 }
1212
1213
1214 /* process dialing 'test'
1215  */
1216 void EndpointAppPBX::action_dialing_test(void)
1217 {
1218         unsigned int cause;
1219         char causestr[16];
1220         struct port_list *portlist = ea_endpoint->ep_portlist;
1221         struct lcr_msg *message;
1222         class Port *port;
1223         char testcode[32] = "";
1224         struct route_param *rparam;
1225
1226         /* given testcode */
1227         if ((rparam = routeparam(e_action, PARAM_PREFIX)))
1228                 SCPY(testcode, rparam->string_value);
1229         SCAT(testcode, e_extdialing);
1230
1231         switch(testcode[0]) {
1232                 case '1':
1233                 trace_header("ACTION test", DIRECTION_NONE);
1234                 add_trace("test", NULL, "proceeding");
1235                 end_trace();
1236                 new_state(EPOINT_STATE_IN_PROCEEDING);
1237                 set_tone(portlist, "proceeding");
1238                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
1239                 message_put(message);
1240                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1241                 break;
1242                 
1243                 case '2':
1244                 trace_header("ACTION test", DIRECTION_NONE);
1245                 add_trace("test", NULL, "alerting");
1246                 end_trace();
1247                 new_state(EPOINT_STATE_IN_ALERTING);
1248                 set_tone(portlist, "ringpbx");
1249                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
1250                 message_put(message);
1251                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1252                 break;
1253                 
1254                 case '3':
1255                 trace_header("ACTION test", DIRECTION_NONE);
1256                 add_trace("test", NULL, "echo");
1257                 end_trace();
1258                 new_state(EPOINT_STATE_CONNECT);
1259                 if (e_ext.number[0])
1260                         e_dtmf = 1;
1261                 set_tone(portlist, NULL);
1262                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1263                 SCPY(e_connectinfo.id, e_callerinfo.id);
1264                 SCPY(e_connectinfo.extension, e_callerinfo.extension);
1265                 e_connectinfo.itype = e_callerinfo.itype;
1266                 e_connectinfo.ntype = e_callerinfo.ntype;
1267                 e_connectinfo.present = e_callerinfo.present;
1268                 e_connectinfo.screen = e_callerinfo.screen;
1269                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1270                 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1271                 /* handle restricted caller ids */
1272                 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);
1273                 /* display callerid if desired for extension */
1274                 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));
1275                 message_put(message);
1276                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1277
1278                 port = find_port_id(portlist->port_id);
1279                 if (port) {
1280                         port->set_echotest(1);
1281                 }
1282                 break;
1283                 
1284                 case '4':
1285                 trace_header("ACTION test", DIRECTION_NONE);
1286                 add_trace("test", NULL, "tone");
1287                 end_trace();
1288                 new_state(EPOINT_STATE_CONNECT);
1289                 if (e_ext.number[0])
1290                         e_dtmf = 1;
1291                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1292                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1293                 message_put(message);
1294                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1295                 set_tone(portlist, "test");
1296                 break;
1297                 
1298                 case '5':
1299                 trace_header("ACTION test", DIRECTION_NONE);
1300                 add_trace("test", NULL, "hold music");
1301                 end_trace();
1302                 new_state(EPOINT_STATE_CONNECT);
1303                 if (e_ext.number[0])
1304                         e_dtmf = 1;
1305                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1306                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1307                 message_put(message);
1308                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1309                 set_tone(portlist, "hold");
1310                 break;
1311                 
1312                 case '6':
1313                 if (strlen(testcode) < 4)
1314                         break;
1315                 testcode[4] = '\0';
1316                 cause = atoi(testcode+1);
1317                 if (cause > 255)
1318                         cause = 0;
1319                 trace_header("ACTION test", DIRECTION_NONE);
1320                 add_trace("test", NULL, "announcement");
1321                 add_trace("cause", NULL, "%d", cause);
1322                 end_trace();
1323                 new_state(EPOINT_STATE_CONNECT);
1324                 if (e_ext.number[0])
1325                         e_dtmf = 1;
1326                 SPRINT(causestr,"cause_%02x",cause);
1327                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1328                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1329                 message_put(message);
1330                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1331                 set_tone(portlist, causestr);
1332                 break;
1333                 
1334                 case '7':
1335                 if (strlen(testcode) < 4)
1336                         break;
1337                 testcode[4] = '\0';
1338                 cause = atoi(testcode+1);
1339                 if (cause > 127)
1340                         cause = 0;
1341                 trace_header("ACTION test", DIRECTION_NONE);
1342                 add_trace("test", NULL, "disconnect");
1343                 add_trace("cause", NULL, "%d", cause);
1344                 end_trace();
1345                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1346                 SPRINT(causestr,"cause_%02x",cause);
1347                 message_disconnect_port(portlist, cause, LOCATION_PRIVATE_LOCAL, "");
1348                 set_tone(portlist, causestr);
1349                 break;
1350
1351                 case '8': /* release */
1352                 trace_header("ACTION test", DIRECTION_NONE);
1353                 add_trace("test", NULL, "release");
1354                 add_trace("cause", NULL, "16");
1355                 end_trace();
1356                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1357                 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1358                 set_tone(portlist, "release");
1359                 break;
1360
1361                 case '9': /* text callerid test */
1362                 trace_header("ACTION test", DIRECTION_NONE);
1363                 add_trace("test", NULL, "callerid");
1364                 end_trace();
1365                 new_state(EPOINT_STATE_CONNECT);
1366                 if (e_ext.number[0])
1367                         e_dtmf = 1;
1368                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1369                 SCPY(e_connectinfo.id, "12345678");
1370                 SCPY(e_connectinfo.name, "Welcome to LCR");
1371                 SCPY(e_connectinfo.display, "Welcome to LCR");
1372                 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1373                 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1374                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1375                 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(message->param.connectinfo));
1376                 message_put(message);
1377                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1378                 set_tone(portlist, "hold");
1379                 break;
1380         }
1381 }
1382
1383
1384 /* process init play
1385  */
1386 void EndpointAppPBX::action_init_play(void)
1387 {
1388         struct route_param *rparam;
1389         struct port_list *portlist = ea_endpoint->ep_portlist;
1390
1391         /* check given sample */
1392         if (!(rparam = routeparam(e_action, PARAM_SAMPLE))) {
1393                 trace_header("ACTION play (no sample given)", DIRECTION_NONE);
1394                 end_trace();
1395
1396                 disconnect:
1397                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1398                 message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
1399                 set_tone(portlist, "cause_3f");
1400                 e_action = NULL;
1401                 return;
1402         }
1403
1404         /* if sample is given */
1405         if (rparam->string_value[0] == '\0') {
1406                 trace_header("ACTION play (no sample given)", DIRECTION_NONE);
1407                 end_trace();
1408                 goto disconnect;
1409         }
1410
1411         if (e_ext.number[0])
1412                 e_dtmf = 1;
1413
1414         set_tone(ea_endpoint->ep_portlist, rparam->string_value);
1415 }
1416
1417
1418 /*
1419  * action_*_vbox_play is implemented in "action_vbox.cpp"
1420  */
1421
1422
1423 /*
1424  * process dialing of calculator
1425  */
1426 void EndpointAppPBX::action_dialing_calculator(void)
1427 {
1428         struct port_list *portlist = ea_endpoint->ep_portlist;
1429         struct lcr_msg *message;
1430         double value1, value2, v, sign1;
1431         int komma1, komma2, k, state, mode = 0, first;
1432         char *p;
1433
1434         portlist = ea_endpoint->ep_portlist;
1435
1436         /* remove error message */
1437         if (!strncmp(e_extdialing, "Error", 5)) {
1438                 UCPY(e_extdialing, e_extdialing+5);
1439         }
1440         if (!strncmp(e_extdialing, "inf", 3)) {
1441                 UCPY(e_extdialing, e_extdialing+3);
1442         }
1443         if (!strncmp(e_extdialing, "-inf", 4)) {
1444                 UCPY(e_extdialing, e_extdialing+4);
1445         }
1446
1447         /* process dialing */
1448         state = 0;
1449         value1 = 0;
1450         value2 = 0;
1451         komma1 = 0;
1452         komma2 = 0;
1453         sign1 = 1;
1454         p = e_extdialing;
1455         if (!p)
1456                 return;
1457         first = 1;
1458         while(*p) {
1459                 if (*p>='0' && *p<='9') {
1460 #if 0
1461                         if (first) {
1462                                 UCPY(p, p+1);
1463                                 continue;
1464                         }
1465                         if ((p[-1]<'0' || p[-1]>'0') && p[-1]!='.') {
1466                                 p--;
1467                                 UCPY(p, p+1);
1468                                 continue;
1469                         }
1470 #endif
1471                         switch(state) {
1472                                 case 0: /* first number */
1473                                 if (!komma1) {
1474                                         value1 = value1*10 + (*p-'0');
1475                                 } else {
1476                                         k = komma1++;
1477                                         v = *p-'0';
1478                                         while(k--)
1479                                                 v /= 10;
1480                                         value1 += v; 
1481                                 }
1482                                 break;
1483                                 case 1: /* second number */
1484                                 if (!komma2) {
1485                                         value2 = value2*10 + (*p-'0');
1486                                 } else {
1487                                         k = komma2++;
1488                                         v = *p-'0';
1489                                         while(k--)
1490                                                 v /= 10;
1491                                         value2 += v; 
1492                                 }
1493                                 break;
1494                         }
1495                 } else
1496                 switch(*p) {
1497                         case '*':
1498                         if (first) {
1499                                 UCPY(e_extdialing, "Error");
1500                                 goto done;
1501                         }
1502                         /* if there is a multiplication, we change to / */
1503                         if (p[-1] == '*') {
1504                                 mode = 1;
1505                                 p[-1] = '/';
1506                                 UCPY(p, p+1);
1507                                 p--;
1508                                 break;
1509                         }
1510                         /* if there is a division, we change to + */
1511                         if (p[-1] == '/') {
1512                                 mode = 2;
1513                                 p[-1] = '+';
1514                                 UCPY(p, p+1);
1515                                 p--;
1516                                 break;
1517                         }
1518                         /* if there is a addition, we change to - */
1519                         if (p[-1] == '+') {
1520                                 mode = 3;
1521                                 p[-1] = '-';
1522                                 UCPY(p, p+1);
1523                                 p--;
1524                                 break;
1525                         }
1526                         /* if there is a substraction and a comma, we change to * */
1527                         if (p[-1]=='-' && komma1) {
1528                                 mode = 0;
1529                                 p[-1] = '*';
1530                                 UCPY(p, p+1);
1531                                 p--;
1532                                 break;
1533                         }
1534                         /* if there is a substraction and no comma and the first or second value, we change to , */
1535                         if (p[-1]=='-') {
1536                                 p[-1] = '.';
1537                                 UCPY(p, p+1);
1538                                 p--;
1539                                 komma1 = 1;
1540                                 break;
1541                         }
1542                         /* if there is a komma and we are at the first value, we change to * */
1543                         if (p[-1]=='.' && state==0) {
1544                                 mode = 0;
1545                                 p[-1] = '*';
1546                                 UCPY(p, p+1);
1547                                 p--;
1548                                 komma1 = 0;
1549                                 break;
1550                         }
1551                         /* if there is a komma and we are at the second value, we display error */
1552                         if (komma2 && state==1) {
1553                                 UCPY(e_extdialing, "Error");
1554                                 goto done;
1555                         }
1556                         /* if we are at state 1, we write a comma */
1557                         if (state == 1) {
1558                                 *p = '.';
1559                                 komma2 = 1;
1560                                 break;
1561                         }
1562                         /* we assume multiplication */
1563                         mode = 0;
1564                         state = 1;
1565                         komma1 = 0;
1566                         break;
1567
1568                         case '#':
1569                         /* if just a number is displayed, the input is cleared */
1570                         if (state==0) {
1571                                 *e_extdialing = '\0';
1572                                 break;
1573                         }
1574                         /* calculate the result */
1575                         switch(mode) {
1576                                 case 0: /* multiply */
1577                                 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1*value2);
1578                                 break;
1579                                 case 1: /* divide */
1580                                 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1/value2);
1581                                 break;
1582                                 case 2: /* add */
1583                                 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1+value2);
1584                                 break;
1585                                 case 3: /* substract */
1586                                 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1-value2);
1587                                 break;
1588                         }
1589                         e_dialinginfo.id[sizeof(e_dialinginfo.id)-1] = '\0';
1590                         if (strchr(e_extdialing, '.')) { /* remove zeroes */
1591                                 while (e_extdialing[strlen(e_extdialing)-1] == '0')
1592                                         e_extdialing[strlen(e_extdialing)-1] = '\0';
1593                                 if (e_extdialing[strlen(e_extdialing)-1] == '.')
1594                                         e_extdialing[strlen(e_extdialing)-1] = '\0'; /* and remove dot */
1595                         }
1596                         p = strchr(e_extdialing,'\0')-1;
1597                         break;
1598
1599                         case '.':
1600                         if (state)
1601                                 komma2 = 1;
1602                         else    komma1 = 1;
1603                         break;
1604
1605                         case '/':
1606                         komma2 = 0;
1607                         state = 1;
1608                         mode = 1;
1609                         break;
1610
1611                         case '+':
1612                         komma2 = 0;
1613                         state = 1;
1614                         mode = 2;
1615                         break;
1616
1617                         case '-':
1618                         if (first) {
1619                                 sign1=-1;
1620                                 break;
1621                         }
1622                         komma2 = 0;
1623                         state = 1;
1624                         mode = 3;
1625                         break;
1626
1627                         default:
1628                         UCPY(e_extdialing, "Error");
1629                         goto done;
1630                 }
1631
1632                 p++;
1633                 first = 0;
1634         }
1635         done:
1636
1637         /* display dialing */   
1638         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1639         SPRINT(message->param.notifyinfo.display, ">%s", e_extdialing);
1640         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s displaying interpreted dialing '%s' internal values: %f %f\n", ea_endpoint->ep_serial, e_ext.number, e_extdialing, value1, value2);
1641         message_put(message);
1642         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1643
1644 }
1645
1646 /*
1647  * process dialing of timer
1648  */
1649 void EndpointAppPBX::action_dialing_timer(void)
1650 {
1651 }
1652
1653
1654 /*
1655  * process 'goto' or 'menu'
1656  */
1657 void EndpointAppPBX::_action_goto_menu(int mode)
1658 {
1659         struct port_list *portlist = ea_endpoint->ep_portlist;
1660         struct route_param *rparam;
1661
1662         /* check given ruleset */
1663         if (!(rparam = routeparam(e_action, PARAM_RULESET))) {
1664                 no_ruleset:
1665                 trace_header("ACTION goto/menu (no ruleset given)", DIRECTION_NONE);
1666                 end_trace();
1667
1668                 disconnect:
1669                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1670                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1671                 set_tone(portlist, "cause_3f");
1672                 e_action = NULL;
1673                 return;
1674         }
1675         if (rparam->string_value[0] == '\0')
1676                 goto no_ruleset;
1677         e_ruleset = getrulesetbyname(rparam->string_value);
1678         if (!e_ruleset) {
1679                 trace_header("ACTION goto/menu (ruleset not found)", DIRECTION_NONE);
1680                 add_trace("ruleset", NULL, "%s", rparam->string_value);
1681                 end_trace();
1682                 goto disconnect;
1683         }
1684
1685         /* if the 'menu' was selected, we will flush all digits */
1686         if (mode) {
1687                 e_dialinginfo.id[0] = 0;
1688                 e_extdialing = e_dialinginfo.id;
1689         } else {
1690                 /* remove digits that are required to match the rule */
1691                 if ((rparam = routeparam(e_action, PARAM_STRIP))) {
1692                         if (e_extdialing)
1693                                 SCPY(e_dialinginfo.id, e_extdialing);
1694                         e_extdialing = e_dialinginfo.id;
1695                 }
1696         }
1697
1698         /* play sample */
1699         trace_header("ACTION goto/menu (change to)", DIRECTION_NONE);
1700         add_trace("ruleset", NULL, "%s", e_ruleset->name);
1701         if (e_dialinginfo.id[0]) {
1702                 add_trace("dialing", NULL, "%s", e_dialinginfo.id);
1703         }
1704         if ((rparam = routeparam(e_action, PARAM_SAMPLE))) {
1705                 add_trace("sample", NULL, "%s", rparam->string_value);
1706                 end_trace();
1707                 set_tone(ea_endpoint->ep_portlist, rparam->string_value);
1708         } else {
1709                 end_trace();
1710         }
1711
1712         /* do dialing with new ruleset */
1713         e_action = NULL;
1714         process_dialing(0);
1715 }
1716
1717 /* process dialing goto
1718 */
1719 void EndpointAppPBX::action_dialing_goto(void)
1720 {
1721         _action_goto_menu(0);
1722 }
1723
1724 /* process dialing menu
1725 */
1726 void EndpointAppPBX::action_dialing_menu(void)
1727 {
1728         _action_goto_menu(1);
1729 }
1730
1731
1732 /*
1733  * process dialing disconnect
1734  */
1735 void EndpointAppPBX::action_dialing_disconnect(void)
1736 {
1737         struct route_param *rparam;
1738         struct port_list *portlist = ea_endpoint->ep_portlist;
1739         struct lcr_msg *message;
1740         int cause = CAUSE_NORMAL; /* normal call clearing */
1741         int location = LOCATION_PRIVATE_LOCAL;
1742         char cause_string[256] = "", display[84] = "";
1743
1744         /* check cause parameter */
1745         if ((rparam = routeparam(e_action, PARAM_CAUSE))) {
1746                 cause = rparam->integer_value;
1747                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'cause' is given: %d\n", ea_endpoint->ep_serial, cause);
1748         }
1749         if ((rparam = routeparam(e_action, PARAM_LOCATION))) {
1750                 location = rparam->integer_value;
1751                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'location' is given: %d\n", ea_endpoint->ep_serial, location);
1752         }
1753
1754
1755         /* use cause as sample, if not given later */
1756         SPRINT(cause_string, "cause_%02x", cause);
1757
1758         /* check sample parameter */
1759         if ((rparam = routeparam(e_action, PARAM_SAMPLE))) {
1760                 SCPY(cause_string, rparam->string_value);
1761                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'sample' is given: %s\n", ea_endpoint->ep_serial, cause_string);
1762         }
1763
1764         /* check display */
1765         if ((rparam = routeparam(e_action, PARAM_DISPLAY))) {
1766                 SCPY(display, rparam->string_value);
1767                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'display' is given: %s\n", ea_endpoint->ep_serial, display);
1768         }
1769
1770         /* disconnect only if connect parameter is not given */
1771         trace_header("ACTION disconnect", DIRECTION_NONE);
1772         add_trace("cause", "value", "%d", cause);
1773         add_trace("cause", "location", "%d", location);
1774         if (cause_string[0])
1775                 add_trace("sample", NULL, "%s", cause_string);
1776         if (display[0])
1777                 add_trace("display", NULL, "%s", display);
1778         end_trace();
1779         new_state(EPOINT_STATE_OUT_DISCONNECT);
1780         set_tone(portlist, cause_string);
1781         if (!(rparam = routeparam(e_action, PARAM_CONNECT))) {
1782                 message_disconnect_port(portlist, cause, location, display);
1783         } else {
1784                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1785                 SCPY(message->param.notifyinfo.display, display);
1786                 message_put(message);
1787                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1788         }
1789         e_action = NULL;
1790 }
1791
1792
1793 /*
1794  * process dialing release
1795  */
1796 void EndpointAppPBX::action_dialing_release(void)
1797 {
1798         struct route_param *rparam;
1799         int cause = CAUSE_NORMAL; /* normal call clearing */
1800         int location = LOCATION_PRIVATE_LOCAL;
1801         char cause_string[256] = "", display[84] = "";
1802
1803         /* check cause parameter */
1804         if ((rparam = routeparam(e_action, PARAM_CAUSE))) {
1805                 cause = rparam->integer_value;
1806                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'cause' is given: %d\n", ea_endpoint->ep_serial, cause);
1807         }
1808         if ((rparam = routeparam(e_action, PARAM_LOCATION))) {
1809                 location = rparam->integer_value;
1810                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'location' is given: %d\n", ea_endpoint->ep_serial, location);
1811         }
1812
1813
1814         /* use cause as sample, if not given later */
1815         SPRINT(cause_string, "cause_%02x", cause);
1816
1817         /* check display */
1818         if ((rparam = routeparam(e_action, PARAM_DISPLAY))) {
1819                 SCPY(display, rparam->string_value);
1820                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'display' is given: %s\n", ea_endpoint->ep_serial, display);
1821         }
1822
1823         /* disconnect only if connect parameter is not given */
1824         trace_header("ACTION release", DIRECTION_NONE);
1825         add_trace("cause", "value", "%d", cause);
1826         add_trace("cause", "location", "%d", location);
1827         if (display[0])
1828                 add_trace("display", NULL, "%s", display);
1829         end_trace();
1830         e_action = NULL;
1831         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, location, cause, 1);
1832         return;
1833 }
1834
1835 /*
1836  * process dialing help
1837  */
1838 void EndpointAppPBX::action_dialing_help(void)
1839 {
1840         /* show all things that would match */
1841 #if 0
1842         struct numbering *numbering = numbering_int;
1843         char dialing[sizeof(e_dialinginfo.id)];
1844         int i;
1845         struct lcr_msg *message;
1846         struct route_param *rparam;
1847
1848         /* in case we have no menu (this should never happen) */
1849         if (!numbering)
1850                 return;
1851
1852         /* scroll menu */
1853         if (strchr(e_dialinginfo.id,'*')) {
1854                 e_menu--;
1855                 e_dialinginfo.id[0] = '\0';
1856         }
1857         if (strchr(e_dialinginfo.id,'#')) {
1858                 e_menu++;
1859                 e_dialinginfo.id[0] = '\0';
1860         }
1861         
1862         /* get position in menu */
1863         if (e_menu < 0) {
1864                 /* get last menu position */
1865                 e_menu = 0;
1866                 while(numbering->next) {
1867                         e_menu++;
1868                         numbering = numbering->next;
1869                 }
1870         } else {
1871                 /* get menu position */
1872                 i = 0;
1873                 while(i < e_menu) {
1874                         numbering = numbering->next;
1875                         if (!numbering) {
1876                                 e_menu = 0;
1877                                 numbering = numbering_int;
1878                                 break;
1879                         }
1880                         i++;
1881                 }
1882         }
1883
1884         /* if we dial something else we need to add the prefix and change the action */
1885         if (e_dialinginfo.id[0]) {
1886                 e_action = NUMB_ACTION_NONE;
1887                 SCPY(dialing, numbering->prefix);
1888                 //we ignore the first digit after selecting
1889                 //SCAT(dialing, e_dialinginfo.id);
1890                 SCPY(e_dialinginfo.id, dialing);
1891                 e_extdialing = e_dialinginfo.id+strlen(numbering->prefix);
1892                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' dialing: %s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], e_dialinginfo.id);
1893 nesting?:
1894                 process_dialing(0);
1895                 return;
1896         }
1897
1898         /* send display message to port */
1899         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1900         SPRINT(message->param.notifyinfo.display, ">%s %s%s%s", numbering->prefix, numb_actions[numbering->action], (numbering->param[0])?" ":"", numbering->param);
1901         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' sending display:%s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], message->param.notifyinfo.display);
1902         message_put(message);
1903         logmessage(message->type, message->paramea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1904 #endif
1905 }
1906
1907
1908 /*
1909  * process dialing deflect
1910  */
1911 void EndpointAppPBX::action_dialing_deflect(void)
1912 {
1913 }
1914
1915
1916 /*
1917  * process dialing setforward
1918  */
1919 void EndpointAppPBX::action_dialing_setforward(void)
1920 {
1921 }
1922
1923 /*
1924  * process init 'execute'
1925  */ 
1926 void EndpointAppPBX::action_init_execute(void)
1927 {
1928         struct route_param *rparam;
1929         int executeon = INFO_ON_HANGUP;  /* Use Hangup as a default for compatibility */
1930         
1931         /* Get the execute on parameter */
1932         if ((rparam = routeparam(e_action, PARAM_ON)))
1933         executeon = rparam->integer_value;
1934
1935         /* Execute this action if init was specified */
1936         if (executeon == INFO_ON_INIT) {
1937                 trace_header("ACTION execute ON init", DIRECTION_NONE);
1938                 end_trace();
1939                 action_execute();
1940         }
1941 }
1942
1943 /*
1944  * process hangup 'execute'
1945  */ 
1946 void EndpointAppPBX::action_hangup_execute(void)
1947 {
1948         struct route_param *rparam;
1949         int executeon = INFO_ON_HANGUP;  /* Use Hangup as a default for compatibility */
1950         
1951         /* Get the execute on parameter */
1952         if ((rparam = routeparam(e_action, PARAM_ON)))
1953         executeon = rparam->integer_value;
1954
1955         /* Execute this action if init was specified */
1956         if (executeon == INFO_ON_HANGUP) {
1957                 trace_header("ACTION execute ON hangup", DIRECTION_NONE);
1958                 end_trace();
1959                 action_execute();
1960         }
1961 }
1962
1963 /*
1964  * process 'execute' from action_init_execute or action_hangup_execute
1965  */
1966 void EndpointAppPBX::action_execute(void)
1967 {
1968         struct route_param *rparam;
1969         pid_t pid;
1970         pid_t pid2;
1971         int iWaitStatus;
1972         char *command = (char *)"";
1973         char isdn_port[10];
1974         char *argv[12]; /* check also number of args below */
1975         int i = 0;
1976
1977         /* get script / command */
1978         if ((rparam = routeparam(e_action, PARAM_EXECUTE)))
1979                 command = rparam->string_value;
1980         if (command[0] == '\0') {
1981                 trace_header("ACTION execute (no parameter given)", DIRECTION_NONE);
1982                 end_trace();
1983                 return;
1984         }
1985 #if 0
1986         argv[i++] = (char *)"/bin/sh";
1987         argv[i++] = (char *)"-c";
1988         argv[i++] = command;
1989 #endif
1990         argv[i++] = command;
1991         if ((rparam = routeparam(e_action, PARAM_PARAM))) {
1992                 argv[i++] = rparam->string_value;
1993         }
1994         argv[i++] = e_extdialing;
1995         argv[i++] = (char *)numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international);
1996         argv[i++] = e_callerinfo.extension;
1997         argv[i++] = e_callerinfo.name;
1998         SPRINT(isdn_port, "%d", e_callerinfo.isdn_port);
1999         argv[i++] = isdn_port;
2000         argv[i++] = e_callerinfo.imsi;
2001         argv[i++] = NULL; /* check also number of args above */
2002         switch (pid = fork ()) {
2003                 case -1:
2004                         trace_header("ACTION execute (fork failed)", DIRECTION_NONE);
2005                         end_trace();
2006                         break;
2007                 case 0:
2008                         /* To be shure there are no zombies created double fork */
2009                         if ((pid2 = fork()) == 0) {
2010                                 execve(command, argv, environ);
2011                         }
2012                         /* Exit immediately and release the waiting parent. The subprocess falls to init because the parent died */
2013                         exit(0);
2014                         break;
2015                 default:
2016                         trace_header("ACTION execute", DIRECTION_NONE);
2017                         add_trace("command", NULL, "%s", command);
2018                         end_trace();
2019
2020                         /* Wait for the pid. The forked process will exit immediately so there is no problem waiting. */
2021                         waitpid(pid, &iWaitStatus, 0);
2022                         break;
2023         }
2024 }
2025
2026
2027 /*
2028  * process hangup 'file'
2029  */
2030 void EndpointAppPBX::action_hangup_file(void)
2031 {
2032         struct route_param *rparam;
2033         const char *file, *content, *mode;
2034         FILE *fp;
2035
2036         /* get file / content */
2037         if (!(rparam = routeparam(e_action, PARAM_FILE)))
2038                 file = rparam->string_value;
2039         else
2040                 file = "";
2041         if (!(rparam = routeparam(e_action, PARAM_CONTENT)))
2042                 content = rparam->string_value;
2043         else
2044                 content = e_extdialing;
2045         if (!(rparam = routeparam(e_action, PARAM_APPEND)))
2046                 mode = "a";
2047         else
2048                 mode = "w";
2049         if (file[0] == '\0') {
2050                 trace_header("ACTION file (no filename given)", DIRECTION_NONE);
2051                 end_trace();
2052                 return;
2053         }
2054         if (!(fp = fopen(file, mode))) {
2055                 trace_header("ACTION file (failed to open)", DIRECTION_NONE);
2056                 add_trace("file", "name", "%s", file);
2057                 add_trace("file", "mode", "%s", (mode[0]=='w')?"write":"append");
2058                 end_trace();
2059                 return;
2060         }
2061         trace_header("ACTION file", DIRECTION_NONE);
2062         add_trace("file", "name", "%s", file);
2063         add_trace("file", "mode", "%s", (mode[0]=='w')?"write":"append");
2064         add_trace("content", NULL, "%s", content);
2065         end_trace();
2066         fprintf(fp, "%s\n", content);
2067         fclose(fp);
2068 }
2069
2070
2071 /*
2072  * process init 'pick'
2073  */
2074 void EndpointAppPBX::action_init_pick(void)
2075 {
2076         struct route_param *rparam;
2077         char *extensions = NULL;
2078
2079         if ((rparam = routeparam(e_action, PARAM_EXTENSIONS)))
2080                 extensions = rparam->string_value;
2081         
2082         trace_header("ACTION pick", DIRECTION_NONE);
2083         if (extensions) if (extensions[0])
2084                 add_trace("extensions", NULL, "%s", extensions);
2085         end_trace();
2086         pick_join(extensions);
2087 }
2088
2089
2090 /*
2091  * process dialing 'password'
2092  */
2093 void EndpointAppPBX::action_dialing_password(void)
2094 {
2095         struct port_list *portlist = ea_endpoint->ep_portlist;
2096
2097         /* prompt for password */
2098         if (e_extdialing[0] == '\0') {
2099                 /* give password tone */
2100                 set_tone(portlist, "password");
2101         } else // ELSE!!
2102         if (e_extdialing[1] == '\0') {
2103                 /* give password tone */
2104                 set_tone(portlist, "dialing");
2105         }
2106
2107         /* wait until all digits are dialed */
2108         if (strlen(e_ext.password) != strlen(e_extdialing))
2109                 return; /* more digits needed */
2110
2111         /* check the password */
2112         if (e_ext.password[0]=='\0' || (strlen(e_ext.password)==strlen(e_extdialing) && !!strcmp(e_ext.password,e_extdialing))) {
2113                 trace_header("ACTION password_write (wrong password)", DIRECTION_NONE);
2114                 add_trace("dialed", NULL, "%s", e_extdialing);
2115                 end_trace();
2116                 e_connectedmode = 0;
2117                 e_dtmf = 0;
2118                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2119                 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
2120                 set_tone(portlist, "cause_10");
2121                 return;
2122         }
2123
2124         /* write caller id if ACTION_PASSWORD_WRITE was selected */
2125         if (e_action)
2126         if (e_action->index == ACTION_PASSWORD_WRITE) {
2127                 append_callbackauth(e_ext.number, &e_callbackinfo);
2128                 trace_header("ACTION password_write (written)", DIRECTION_NONE);
2129                 add_trace("dialed", NULL, "%s", e_extdialing);
2130                 end_trace();
2131         }
2132
2133         /* make call state  */
2134         new_state(EPOINT_STATE_IN_OVERLAP);
2135         e_ruleset = ruleset_main;
2136         if (e_ruleset)
2137                 e_rule = e_ruleset->rule_first;
2138         e_action = NULL;
2139         e_dialinginfo.id[0] = '\0';
2140         e_extdialing = e_dialinginfo.id;
2141         set_tone(portlist, "dialpbx");
2142 }
2143
2144 void EndpointAppPBX::action_dialing_password_wr(void)
2145 {
2146         action_dialing_password();
2147 }
2148
2149
2150 /* general process dialing of incoming call
2151  * depending on the detected prefix, subfunctions above (action_*) will be
2152  * calles.
2153  */
2154 void EndpointAppPBX::process_dialing(int timeout)
2155 {
2156         struct port_list *portlist = ea_endpoint->ep_portlist;
2157         struct lcr_msg *message;
2158         struct route_param *rparam;
2159         struct timeval current_time;
2160
2161         /* set if timeout is active, or if timeout value was given due to timeout action */
2162         if (e_action_timeout.active)
2163                 timeout = 1;
2164
2165 //#warning Due to HANG-BUG somewhere here, I added some HANG-BUG-DEBUGGING output that cannot be disabled. after bug has been found, this will be removed.
2166 //PDEBUG(~0, "HANG-BUG-DEBUGGING: entered porcess_dialing\n");
2167         portlist = ea_endpoint->ep_portlist;
2168         /* check if we have a port instance linked to our epoint */
2169         if (!portlist) {
2170                 portlist_error:
2171                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): note: dialing call requires exactly one port object to process dialing. this case could happen due to a parked call. we end dialing here.\n", ea_endpoint->ep_serial, e_ext.number);
2172                 unsched_timer(&e_action_timeout);
2173                 unsched_timer(&e_match_timeout);
2174                 return;
2175         }
2176         if (portlist->next) {
2177                 goto portlist_error;
2178         }
2179
2180         /* check nesting levels */
2181         if (++e_rule_nesting > RULE_NESTING) {
2182                 trace_header("ACTION (nesting too deep)", DIRECTION_NONE);
2183                 add_trace("max-levels", NULL, "%d", RULE_NESTING);
2184                 end_trace();
2185                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2186                 message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
2187                 set_tone(portlist, "cause_3f");
2188                 unsched_timer(&e_action_timeout);
2189                 unsched_timer(&e_match_timeout);
2190                 goto end;
2191         }
2192
2193 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before action-timeout processing\n");
2194         /* process timeout */
2195         if (e_action && timeout) { /* e_action may be NULL, but e_action_timeout may still be set and must be ignored */
2196                 unsched_timer(&e_action_timeout);
2197                 if (e_state == EPOINT_STATE_CONNECT) {
2198                         PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, but we already have connected, so we stop timer and continue.\n", ea_endpoint->ep_serial);
2199                         goto end;
2200                 }
2201                 if (e_action->index == ACTION_DISCONNECT
2202                  || e_state == EPOINT_STATE_OUT_DISCONNECT) {
2203                         /* release after disconnect */
2204                         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2205                         goto end;
2206                 }
2207                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0);
2208                 e_action = e_action->next;
2209                 if (!e_action) {
2210                         /* nothing more, so we release */
2211                         PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, and we have no next action, so we disconnect.\n", ea_endpoint->ep_serial);
2212                         new_state(EPOINT_STATE_OUT_DISCONNECT);
2213                         message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
2214                         set_tone(portlist, "cause_3f");
2215                         goto end;
2216                 }
2217                 goto action_timeout;
2218         }
2219
2220 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before setup/overlap state checking\n");
2221         if (e_state!=EPOINT_STATE_IN_SETUP
2222          && e_state!=EPOINT_STATE_IN_OVERLAP) {
2223                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): we are not in incoming setup/overlap state, so we ignore init/dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
2224                 unsched_timer(&e_match_timeout);
2225                 goto end;
2226         }
2227
2228 #if 0
2229         /* check if we do menu selection */
2230         if (e_action==NUMB_ACTION_NONE && (e_dialinginfo.id[0]=='*' || e_dialinginfo.id[0]=='#'))
2231         /* do menu selection */
2232         if (e_ext.display_menu) {
2233                 if (portlist->port_type==PORT_TYPE_DSS1_NT_IN || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) { /* only if the dialing terminal is an isdn telephone connected to an internal port */
2234                         e_dialinginfo.id[0] = '\0';
2235                         e_action = NUMB_ACTION_MENU;
2236                         e_menu = 0;
2237                         process_dialing(0);
2238                         unsched_timer(&e_match_timeout);
2239                         goto end;
2240                 }
2241                 /* invalid dialing */
2242                 message_disconnect_port(portlist, CAUSE_INCALID, LOCATION_PRIVATE_LOCAL, "");
2243                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
2244                         message->param.disconnectinfo.cause = CAUSE_INVALID;
2245                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2246                                 } else {
2247                                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2248                                         SCPY(message->param.notifyinfo.display,get_isdn_cause(LOCATION_PRIVATE_LOCAL, epoint->e_ext.display_cause, param->disconnectinfo.location, param->disconnectinfo.cause));
2249                                 }
2250                         message_put(message);
2251                         logmessage(message->type, message->param, portlist->port_id, DIRECTION_OUT);
2252                 }
2253                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2254                 set_tone(portlist,"cause_1c");
2255                 unsched_timer(&e_match_timeout);
2256                 goto end;
2257         }
2258 #endif
2259
2260 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before e_action==NULL\n");
2261         /* if no action yet, we will call try to find a matching rule */
2262         if (!e_action) {
2263                 /* be sure that all selectors are initialized */
2264                 e_select = 0;
2265
2266                 /* check for external call */
2267                 if (!strncmp(e_dialinginfo.id, "extern:", 7)) {
2268                         e_extdialing = e_dialinginfo.id+7;
2269                         e_action = &action_external;
2270                         goto process_action;
2271                 }
2272                 /* check for internal call */
2273                 if (!strncmp(e_dialinginfo.id, "intern:", 7)) {
2274                         e_extdialing = e_dialinginfo.id+7;
2275                         e_action = &action_internal;
2276                         goto process_action;
2277                 }
2278                 /* check for chan call */
2279                 if (!strncmp(e_dialinginfo.id, "remote:", 7)) {
2280                         e_extdialing = e_dialinginfo.id+7;
2281                         e_action = &action_remote;
2282                         goto process_action;
2283                 }
2284                 /* check for vbox call */
2285                 if (!strncmp(e_dialinginfo.id, "vbox:", 5)) {
2286                         e_extdialing = e_dialinginfo.id+5;
2287                         e_action = &action_vbox;
2288                         goto process_action;
2289                 }
2290
2291                 gettimeofday(&current_time, NULL);
2292                 if (e_match_to_action && TIME_SMALLER(&e_match_timeout.timeout, &current_time)) {
2293                         /* return timeout rule */
2294                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', timeout in ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name);
2295                         unsched_timer(&e_match_timeout);
2296                         e_action = e_match_to_action;
2297                         e_match_to_action = NULL;
2298                         e_extdialing = e_match_to_extdialing;
2299                         trace_header("ROUTING (timeout)", DIRECTION_NONE);
2300                         add_trace("action", NULL, "%s", action_defs[e_action->index].name);
2301                         add_trace("line", NULL, "%d", e_action->line);
2302                         end_trace();
2303                 } else {
2304 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before routing\n");
2305                         /* check for matching rule */
2306                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', checking matching rule of ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name);
2307                         if (e_ruleset) {
2308                                 e_action = route(e_ruleset);
2309                                 if (e_action) {
2310                                         trace_header("ACTION (match)", DIRECTION_NONE);
2311                                         add_trace("action", NULL, "%s", action_defs[e_action->index].name);
2312                                         add_trace("line", NULL, "%d", e_action->line);
2313                                         end_trace();
2314                                 }
2315                         } else {
2316                                 e_action = &action_disconnect;
2317                                 if (e_action) {
2318                                         trace_header("ACTION (no main ruleset, disconnecting)", DIRECTION_NONE);
2319                                         end_trace();
2320                                 }
2321                         }
2322 //PDEBUG(~0, "HANG-BUG-DEBUGGING: after routing\n");
2323                 }
2324                 if (!e_action) {
2325                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): no rule within the current ruleset matches yet.\n", ea_endpoint->ep_serial, e_ext.number);
2326                         goto display;
2327                 }
2328
2329                 /* matching */
2330                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): a rule with action '%s' matches.\n", ea_endpoint->ep_serial, action_defs[e_action->index].name);
2331
2332                 action_timeout:
2333
2334                 /* set timeout */
2335                 unsched_timer(&e_action_timeout);
2336                 if (e_action->timeout) {
2337                         schedule_timer(&e_action_timeout, e_action->timeout, 0);
2338                         PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action has a timeout of %d secods.\n", ea_endpoint->ep_serial, e_action->timeout);
2339                 }
2340
2341                 process_action:
2342                 /* check param proceeding / alerting / connect */
2343                 if ((rparam = routeparam(e_action, PARAM_CONNECT))) {
2344                         /* NOTE: we may not change our state to connect, because dialing will then not possible */
2345                         e_dtmf = 1;
2346                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2347                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2348                         message_put(message);
2349                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2350                 } else
2351                 if ((rparam = routeparam(e_action, PARAM_ALERTING))) {
2352                         /* NOTE: we may not change our state to alerting, because dialing will then not possible */
2353                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2354                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2355                         message_put(message);
2356                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2357                 } else
2358                 if ((rparam = routeparam(e_action, PARAM_PROCEEDING))) {
2359                         /* NOTE: we may not change our state to proceeding, because dialing will then not possible */
2360                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2361                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2362                         message_put(message);
2363                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2364                 }
2365
2366                 if (action_defs[e_action->index].init_func) {
2367                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: current action '%s' has a init function, so we call it...\n", ea_endpoint->ep_serial, e_ext.number, action_defs[e_action->index].name);
2368                         (this->*(action_defs[e_action->index].init_func))();
2369                 }
2370                 if (e_state!=EPOINT_STATE_IN_SETUP
2371                  && e_state!=EPOINT_STATE_IN_OVERLAP) {
2372                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): AFTER init process: we are not in incoming setup/overlap state anymore, so we ignore further dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
2373                         goto display_action;
2374                 }
2375         }
2376
2377         /* show what we are doing */
2378         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' action: %s (dialing '%s')\n", ea_endpoint->ep_serial, e_ext.number, action_defs[e_action->index].name, e_extdialing);
2379         /* go to action's dialing function */
2380         if (action_defs[e_action->index].dialing_func) {
2381                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: current action '%s' has a dialing function, so we call it...\n", ea_endpoint->ep_serial, e_ext.number, action_defs[e_action->index].name);
2382                 (this->*(action_defs[e_action->index].dialing_func))();
2383         }
2384
2385         /* display selected dialing action if enabled and still in setup state */
2386         display_action:
2387         if (e_action) {
2388                 if (e_action->index==ACTION_MENU
2389                  || e_action->index==ACTION_REDIAL
2390                  || e_action->index==ACTION_REPLY
2391                  || e_action->index==ACTION_TIMER
2392                  || e_action->index==ACTION_CALCULATOR
2393                  || e_action->index==ACTION_TEST)
2394                         goto end;
2395         }
2396         display:
2397         if (!e_ext.display_dialing)
2398                 goto end;
2399         if (e_state==EPOINT_STATE_IN_OVERLAP || e_state==EPOINT_STATE_IN_PROCEEDING || e_state==EPOINT_STATE_IN_ALERTING || e_state==EPOINT_STATE_CONNECT/* || e_state==EPOINT_STATE_IN_DISCONNECT || e_state==EPOINT_STATE_OUT_DISCONNECT*/)
2400         if (portlist->port_type==PORT_TYPE_DSS1_NT_IN || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) { /* only if the dialing terminal is an isdn telephone connected to an internal port */
2401                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2402
2403                 if (!e_action) {
2404                         SPRINT(message->param.notifyinfo.display, "> %s", e_dialinginfo.id);
2405                 } else {
2406                         SPRINT(message->param.notifyinfo.display, "%s%s%s", action_defs[e_action->index].name, (e_extdialing[0])?" ":"", e_extdialing);
2407                 }
2408
2409                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s displaying interpreted dialing '%s'\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
2410                 message_put(message);
2411                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2412         }
2413
2414 end:
2415         e_rule_nesting--;
2416         return;
2417 }
2418
2419
2420 /* some services store information after hangup */
2421 void EndpointAppPBX::process_hangup(int cause, int location)
2422 {
2423         char callertext[256], dialingtext[256];
2424         int writeext = 0, i;
2425
2426         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2427         if (e_ext.number[0]) {
2428                 if (read_extension(&e_ext, e_ext.number))
2429                         writeext = 0x10;
2430
2431                 if (!e_start) {
2432                         time(&e_start);
2433                         e_stop = 0;
2434                 } else
2435                 if (!e_stop)
2436                         time(&e_stop);
2437                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): writing connect from %s to %s into logfile of %s\n", ea_endpoint->ep_serial, e_callerinfo.id, e_dialinginfo.id, e_ext.number);
2438                 switch(e_dialinginfo.itype) {
2439                         case INFO_ITYPE_CHAN:
2440                         SPRINT(dialingtext, "chan:%s", e_dialinginfo.id);
2441                         break;
2442                         case INFO_ITYPE_ISDN_EXTENSION:
2443                         SPRINT(dialingtext, "intern:%s", e_dialinginfo.id);
2444                         break;
2445                         case INFO_ITYPE_VBOX:
2446                         SPRINT(dialingtext, "vbox:%s", e_dialinginfo.id);
2447                         break;
2448                         default:
2449                         SPRINT(dialingtext, "%s", e_dialinginfo.id);
2450                 }
2451
2452                 if (e_callerinfo.id[0])
2453                         SPRINT(callertext, "%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
2454                 else
2455                         SPRINT(callertext, "unknown");
2456                 /* allpy restriction */
2457                 if (!e_ext.anon_ignore && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
2458                         SPRINT(callertext, "anonymous");
2459                 if (e_callerinfo.extension[0]) /* add intern if present */
2460                         UNPRINT(strchr(callertext,'\0'), sizeof(callertext)-1+strlen(callertext), " (intern %s)", e_callerinfo.extension);
2461                 write_log(e_ext.number, callertext, dialingtext, e_start, e_stop, 0, cause, location);
2462
2463                 /* store last received call for reply-list */
2464                 if (e_origin == 1) // outgoing to phone is incoming for user
2465                 if (e_callerinfo.id[0] || e_callerinfo.extension[0])
2466                 if (e_ext.anon_ignore || e_callerinfo.present!=INFO_PRESENT_RESTRICTED) {
2467                         if (e_callerinfo.extension[0])
2468                                 SPRINT(callertext, "intern:%s", e_callerinfo.extension);
2469                         else
2470                                 SPRINT(callertext, "extern:%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
2471                         if (!!strcmp(callertext, e_ext.last_in[0])) {
2472                                 i = MAX_REMEMBER-1;
2473                                 while(i) {
2474                                         UCPY(e_ext.last_in[i], e_ext.last_in[i-1]);
2475                                         i--;
2476                                 }
2477                                 SCPY(e_ext.last_in[0], callertext);
2478                                 writeext |= 1; /* store extension later */
2479                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing last received caller id '%s'.\n", ea_endpoint->ep_serial, e_ext.number, e_ext.last_in[0]);
2480                         } else
2481                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last received id '%s' because it is identical with the last one.\n", ea_endpoint->ep_serial, e_ext.number, callertext);
2482                 }
2483
2484                 /* store last made call for reply-list */
2485                 if (e_origin == 0) // incoming from phone is outgoing for user
2486                 if (e_dialinginfo.id[0]) {
2487                         if (!!strcmp(e_dialinginfo.id, e_ext.last_out[0])) {
2488                                 i = MAX_REMEMBER-1;
2489                                 while(i) {
2490                                         UCPY(e_ext.last_out[i], e_ext.last_out[i-1]);
2491                                         i--;
2492                                 }
2493                                 SCPY(e_ext.last_out[0], e_dialinginfo.id);
2494                                 writeext |= 1; /* store extension later */
2495                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing last number '%s'.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
2496                         } else
2497                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last number '%s' because it is identical with the last one.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
2498                 }
2499         }
2500         /* write extension if needed */
2501         if (writeext == 0x11)
2502                 write_extension(&e_ext, e_ext.number);
2503
2504         if (e_action) {
2505                 if (action_defs[e_action->index].hangup_func) {
2506                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: current action '%s' has a hangup function, so we call it...\n", ea_endpoint->ep_serial, e_ext.number, action_defs[e_action->index].name);
2507                         (this->*(action_defs[e_action->index].hangup_func))();
2508                 }
2509         }
2510 }
2511