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