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