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