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