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