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