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