b77d9378599181863db3fab0710203a206e0bd47
[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_ISDN_EXTENSION;
137         SCPY(dialinginfo.id, e_dialinginfo.id);
138
139         /* process extension */
140         if ((rparam = routeparam(e_action, PARAM_EXTENSION)))
141                 SCPY(dialinginfo.id, 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.id) && !strchr(dialinginfo.id,','))
183         {
184                 trace_header("ACTION extension (extension doesn't exist)", DIRECTION_NONE);
185                 add_trace("extension", NULL, dialinginfo.id);
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.id);
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.id);
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_ISDN;
262         dialinginfo.sending_complete = 0;
263         SCPY(dialinginfo.id, e_extdialing);
264
265         /* process prefix */
266         if ((rparam = routeparam(e_action, PARAM_PREFIX)))
267                 SPRINT(dialinginfo.id, "%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.id, 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.id, 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.id, 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.id);
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.id, rparam->string_value);
455
456         /* append special announcement (if given) */
457         if ((rparam = routeparam(e_action, PARAM_ANNOUNCEMENT)))
458         if (rparam->string_value[0])
459         {
460                 SCAT(dialinginfo.id, ",");
461                 SCAT(dialinginfo.id, 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", dialinginfo.id);
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", partyline);
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.id);
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.id);
590                 return;
591         }
592         if (e_dialinginfo.id[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.id, 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.id);
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.id);
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.id);
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, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, 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.extension, 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.id[0] = '\0';
704                 e_extdialing = strchr(e_dialinginfo.id, '\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.id[0] = '\0';
720                 e_extdialing = e_dialinginfo.id;
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.id, last);
1020                 e_extdialing = e_dialinginfo.id;
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.id, 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.id, phone);
1285         e_extdialing = e_dialinginfo.id;
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.extension, e_callerinfo.extension);
1343                 e_connectinfo.itype = e_callerinfo.itype;
1344                 e_connectinfo.ntype = e_callerinfo.ntype;
1345                 e_connectinfo.present = e_callerinfo.present;
1346                 e_connectinfo.screen = e_callerinfo.screen;
1347                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1348                 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1349                 /* handle restricted caller ids */
1350                 apply_callerid_restriction(e_ext.anon_ignore, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
1351                 /* display callerid if desired for extension */
1352                 SCPY(message->param.connectinfo.display, apply_callerid_display(message->param.connectinfo.id, message->param.connectinfo.itype, message->param.connectinfo.ntype, message->param.connectinfo.present, message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name));
1353                 message_put(message);
1354                 logmessage(message);
1355
1356                 port = find_port_id(portlist->port_id);
1357                 if (port)
1358                 {
1359                         port->set_echotest(1);
1360                 }
1361                 break;
1362                 
1363                 case '4':
1364                 trace_header("ACTION test", DIRECTION_NONE);
1365                 add_trace("test", NULL, "tone");
1366                 end_trace();
1367                 new_state(EPOINT_STATE_CONNECT);
1368                 if (e_ext.number[0])
1369                         e_dtmf = 1;
1370                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1371                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1372                 message_put(message);
1373                 logmessage(message);
1374                 set_tone(portlist, "test");
1375                 break;
1376                 
1377                 case '5':
1378                 trace_header("ACTION test", DIRECTION_NONE);
1379                 add_trace("test", NULL, "hold music");
1380                 end_trace();
1381                 new_state(EPOINT_STATE_CONNECT);
1382                 if (e_ext.number[0])
1383                         e_dtmf = 1;
1384                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1385                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1386                 message_put(message);
1387                 logmessage(message);
1388                 set_tone(portlist, "hold");
1389                 break;
1390                 
1391                 case '6':
1392                 if (strlen(testcode) < 4)
1393                         break;
1394                 testcode[4] = '\0';
1395                 cause = atoi(testcode+1);
1396                 if (cause > 255)
1397                         cause = 0;
1398                 trace_header("ACTION test", DIRECTION_NONE);
1399                 add_trace("test", NULL, "announcement");
1400                 add_trace("cause", NULL, "%d", cause);
1401                 end_trace();
1402                 new_state(EPOINT_STATE_CONNECT);
1403                 if (e_ext.number[0])
1404                         e_dtmf = 1;
1405                 SPRINT(causestr,"cause_%02x",cause);
1406                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1407                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1408                 message_put(message);
1409                 logmessage(message);
1410                 set_tone(portlist, causestr);
1411                 break;
1412                 
1413                 case '7':
1414                 if (strlen(testcode) < 4)
1415                         break;
1416                 testcode[4] = '\0';
1417                 cause = atoi(testcode+1);
1418                 if (cause > 127)
1419                         cause = 0;
1420                 trace_header("ACTION test", DIRECTION_NONE);
1421                 add_trace("test", NULL, "disconnect");
1422                 add_trace("cause", NULL, "%d", cause);
1423                 end_trace();
1424                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1425                 SPRINT(causestr,"cause_%02x",cause);
1426                 message_disconnect_port(portlist, cause, LOCATION_PRIVATE_LOCAL, "");
1427                 set_tone(portlist, causestr);
1428                 break;
1429
1430                 case '8': /* release */
1431                 trace_header("ACTION test", DIRECTION_NONE);
1432                 add_trace("test", NULL, "release");
1433                 add_trace("cause", NULL, "16");
1434                 end_trace();
1435                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1436                 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1437                 set_tone(portlist, "release");
1438                 break;
1439
1440                 case '9': /* text callerid test */
1441                 trace_header("ACTION test", DIRECTION_NONE);
1442                 add_trace("test", NULL, "callerid");
1443                 end_trace();
1444                 new_state(EPOINT_STATE_CONNECT);
1445                 if (e_ext.number[0])
1446                         e_dtmf = 1;
1447                 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1448                 SCPY(e_connectinfo.id, "12345678");
1449                 SCPY(e_connectinfo.name, "Welcome to LCR");
1450                 SCPY(e_connectinfo.display, "Welcome to LCR");
1451                 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1452                 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1453                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1454                 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(message->param.connectinfo));
1455                 message_put(message);
1456                 logmessage(message);
1457                 set_tone(portlist, "hold");
1458                 break;
1459         }
1460 }
1461
1462
1463 /* process init play
1464  */
1465 void EndpointAppPBX::action_init_play(void)
1466 {
1467         struct route_param *rparam;
1468         struct port_list *portlist = ea_endpoint->ep_portlist;
1469
1470         /* check given sample */
1471         if (!(rparam = routeparam(e_action, PARAM_SAMPLE)))
1472         {
1473                 trace_header("ACTION play (no sample given)", DIRECTION_NONE);
1474                 end_trace();
1475
1476                 disconnect:
1477                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1478                 message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
1479                 set_tone(portlist, "cause_3f");
1480                 e_action = NULL;
1481                 return;
1482         }
1483
1484         /* if sample is given */
1485         if (rparam->string_value[0] == '\0')
1486         {
1487                 trace_header("ACTION play (no sample given)", DIRECTION_NONE);
1488                 end_trace();
1489                 goto disconnect;
1490         }
1491
1492         if (e_ext.number[0])
1493                 e_dtmf = 1;
1494
1495         set_tone(ea_endpoint->ep_portlist, rparam->string_value);
1496 }
1497
1498
1499 /*
1500  * action_*_vbox_play is implemented in "action_vbox.cpp"
1501  */
1502
1503
1504 /*
1505  * process dialing of calculator
1506  */
1507 void EndpointAppPBX::action_dialing_calculator(void)
1508 {
1509         struct port_list *portlist = ea_endpoint->ep_portlist;
1510         struct message *message;
1511         double value1, value2, v, sign1;
1512         int komma1, komma2, k, state, mode, first;
1513         char *p;
1514
1515         portlist = ea_endpoint->ep_portlist;
1516
1517         /* remove error message */
1518         if (!strncmp(e_extdialing, "Error", 5))
1519         {
1520                 UCPY(e_extdialing, e_extdialing+5);
1521         }
1522         if (!strncmp(e_extdialing, "inf", 3))
1523         {
1524                 UCPY(e_extdialing, e_extdialing+3);
1525         }
1526         if (!strncmp(e_extdialing, "-inf", 4))
1527         {
1528                 UCPY(e_extdialing, e_extdialing+4);
1529         }
1530
1531         /* process dialing */
1532         state = 0;
1533         value1 = 0;
1534         value2 = 0;
1535         komma1 = 0;
1536         komma2 = 0;
1537         sign1 = 1;
1538         p = e_extdialing;
1539         if (!p)
1540                 return;
1541         first = 1;
1542         while(*p)
1543         {
1544                 if (*p>='0' && *p<='9')
1545                 {
1546 #if 0
1547                         if (first)
1548                         {
1549                                 UCPY(p, p+1);
1550                                 continue;
1551                         }
1552                         if ((p[-1]<'0' || p[-1]>'0') && p[-1]!='.')
1553                         {
1554                                 p--;
1555                                 UCPY(p, p+1);
1556                                 continue;
1557                         }
1558 #endif
1559                         switch(state)
1560                         {
1561                                 case 0: /* first number */
1562                                 if (!komma1)
1563                                 {
1564                                         value1 = value1*10 + (*p-'0');
1565                                 } else
1566                                 {
1567                                         k = komma1++;
1568                                         v = *p-'0';
1569                                         while(k--)
1570                                                 v /= 10;
1571                                         value1 += v; 
1572                                 }
1573                                 break;
1574                                 case 1: /* second number */
1575                                 if (!komma2)
1576                                 {
1577                                         value2 = value2*10 + (*p-'0');
1578                                 } else
1579                                 {
1580                                         k = komma2++;
1581                                         v = *p-'0';
1582                                         while(k--)
1583                                                 v /= 10;
1584                                         value2 += v; 
1585                                 }
1586                                 break;
1587                         }
1588                 } else
1589                 switch(*p)
1590                 {
1591                         case '*':
1592                         if (first)
1593                         {
1594                                 UCPY(e_extdialing, "Error");
1595                                 goto done;
1596                         }
1597                         /* if there is a multiplication, we change to / */
1598                         if (p[-1] == '*')
1599                         {
1600                                 mode = 1;
1601                                 p[-1] = '/';
1602                                 UCPY(p, p+1);
1603                                 p--;
1604                                 break;
1605                         }
1606                         /* if there is a division, we change to + */
1607                         if (p[-1] == '/')
1608                         {
1609                                 mode = 2;
1610                                 p[-1] = '+';
1611                                 UCPY(p, p+1);
1612                                 p--;
1613                                 break;
1614                         }
1615                         /* if there is a addition, we change to - */
1616                         if (p[-1] == '+')
1617                         {
1618                                 mode = 3;
1619                                 p[-1] = '-';
1620                                 UCPY(p, p+1);
1621                                 p--;
1622                                 break;
1623                         }
1624                         /* if there is a substraction and a comma, we change to * */
1625                         if (p[-1]=='-' && komma1)
1626                         {
1627                                 mode = 0;
1628                                 p[-1] = '*';
1629                                 UCPY(p, p+1);
1630                                 p--;
1631                                 break;
1632                         }
1633                         /* if there is a substraction and no comma and the first or second value, we change to , */
1634                         if (p[-1]=='-')
1635                         {
1636                                 p[-1] = '.';
1637                                 UCPY(p, p+1);
1638                                 p--;
1639                                 komma1 = 1;
1640                                 break;
1641                         }
1642                         /* if there is a komma and we are at the first value, we change to * */
1643                         if (p[-1]=='.' && state==0)
1644                         {
1645                                 mode = 0;
1646                                 p[-1] = '*';
1647                                 UCPY(p, p+1);
1648                                 p--;
1649                                 komma1 = 0;
1650                                 break;
1651                         }
1652                         /* if there is a komma and we are at the second value, we display error */
1653                         if (komma2 && state==1)
1654                         {
1655                                 UCPY(e_extdialing, "Error");
1656                                 goto done;
1657                         }
1658                         /* if we are at state 1, we write a comma */
1659                         if (state == 1)
1660                         {
1661                                 *p = '.';
1662                                 komma2 = 1;
1663                                 break;
1664                         }
1665                         /* we assume multiplication */
1666                         mode = 0;
1667                         state = 1;
1668                         komma1 = 0;
1669                         break;
1670
1671                         case '#':
1672                         /* if just a number is displayed, the input is cleared */
1673                         if (state==0)
1674                         {
1675                                 *e_extdialing = '\0';
1676                                 break;
1677                         }
1678                         /* calculate the result */
1679                         switch(mode)
1680                         {
1681                                 case 0: /* multiply */
1682                                 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1*value2);
1683                                 break;
1684                                 case 1: /* divide */
1685                                 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1/value2);
1686                                 break;
1687                                 case 2: /* add */
1688                                 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1+value2);
1689                                 break;
1690                                 case 3: /* substract */
1691                                 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1-value2);
1692                                 break;
1693                         }
1694                         e_dialinginfo.id[sizeof(e_dialinginfo.id)-1] = '\0';
1695                         if (strchr(e_extdialing, '.')) /* remove zeroes */
1696                         {
1697                                 while (e_extdialing[strlen(e_extdialing)-1] == '0')
1698                                         e_extdialing[strlen(e_extdialing)-1] = '\0';
1699                                 if (e_extdialing[strlen(e_extdialing)-1] == '.')
1700                                         e_extdialing[strlen(e_extdialing)-1] = '\0'; /* and remove dot */
1701                         }
1702                         p = strchr(e_extdialing,'\0')-1;
1703                         break;
1704
1705                         case '.':
1706                         if (state)
1707                                 komma2 = 1;
1708                         else    komma1 = 1;
1709                         break;
1710
1711                         case '/':
1712                         komma2 = 0;
1713                         state = 1;
1714                         mode = 1;
1715                         break;
1716
1717                         case '+':
1718                         komma2 = 0;
1719                         state = 1;
1720                         mode = 2;
1721                         break;
1722
1723                         case '-':
1724                         if (first)
1725                         {
1726                                 sign1=-1;
1727                                 break;
1728                         }
1729                         komma2 = 0;
1730                         state = 1;
1731                         mode = 3;
1732                         break;
1733
1734                         default:
1735                         UCPY(e_extdialing, "Error");
1736                         goto done;
1737                 }
1738
1739                 p++;
1740                 first = 0;
1741         }
1742         done:
1743
1744         /* display dialing */   
1745         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1746         SPRINT(message->param.notifyinfo.display, ">%s", e_extdialing);
1747         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);
1748         message_put(message);
1749         logmessage(message);
1750
1751 }
1752
1753 /*
1754  * process dialing of timer
1755  */
1756 void EndpointAppPBX::action_dialing_timer(void)
1757 {
1758 }
1759
1760
1761 /*
1762  * process 'goto' or 'menu'
1763  */
1764 void EndpointAppPBX::_action_goto_menu(int mode)
1765 {
1766         struct port_list *portlist = ea_endpoint->ep_portlist;
1767         struct route_param *rparam;
1768
1769         /* check given ruleset */
1770         if (!(rparam = routeparam(e_action, PARAM_RULESET)))
1771         {
1772                 no_ruleset:
1773                 trace_header("ACTION goto/menu (no ruleset given)", DIRECTION_NONE);
1774                 end_trace();
1775
1776                 disconnect:
1777                 new_state(EPOINT_STATE_OUT_DISCONNECT);
1778                 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1779                 set_tone(portlist, "cause_3f");
1780                 e_action = NULL;
1781                 return;
1782         }
1783         if (rparam->string_value[0] == '\0')
1784                 goto no_ruleset;
1785         e_ruleset = getrulesetbyname(rparam->string_value);
1786         if (!e_ruleset)
1787         {
1788                 trace_header("ACTION goto/menu (ruleset not found)", DIRECTION_NONE);
1789                 add_trace("ruleset", NULL, "%s", rparam->string_value);
1790                 end_trace();
1791                 goto disconnect;
1792         }
1793
1794         /* if the 'menu' was selected, we will flush all digits */
1795         if (mode)
1796         {
1797                 e_dialinginfo.id[0] = 0;
1798                 e_extdialing = e_dialinginfo.id;
1799         } else
1800         {
1801                 /* remove digits that are required to match the rule */
1802                 if (!(rparam = routeparam(e_action, PARAM_STRIP)))
1803                 {
1804                         if (e_extdialing)
1805                                 SCPY(e_dialinginfo.id, e_extdialing);
1806                         e_extdialing = e_dialinginfo.id;
1807                 }
1808         }
1809
1810         /* play sample */
1811         trace_header("ACTION goto/menu (change to)", DIRECTION_NONE);
1812         add_trace("ruleset", NULL, "%s", e_ruleset->name);
1813         if (e_dialinginfo.id[0])
1814                 add_trace("dialing", NULL, "%s", e_dialinginfo.id);
1815         if ((rparam = routeparam(e_action, PARAM_SAMPLE)))
1816         {
1817                 add_trace("sample", NULL, "%s", rparam->string_value);
1818                 set_tone(ea_endpoint->ep_portlist, rparam->string_value);
1819         }
1820         end_trace();
1821
1822         /* do dialing with new ruleset */
1823         e_action = NULL;
1824         process_dialing();
1825 }
1826
1827 /* process dialing goto
1828 */
1829 void EndpointAppPBX::action_dialing_goto(void)
1830 {
1831         _action_goto_menu(0);
1832 }
1833
1834 /* process dialing menu
1835 */
1836 void EndpointAppPBX::action_dialing_menu(void)
1837 {
1838         _action_goto_menu(1);
1839 }
1840
1841
1842 /*
1843  * process dialing disconnect
1844  */
1845 void EndpointAppPBX::action_dialing_disconnect(void)
1846 {
1847         struct route_param *rparam;
1848         struct port_list *portlist = ea_endpoint->ep_portlist;
1849         struct message *message;
1850         int cause = CAUSE_NORMAL; /* normal call clearing */
1851         int location = LOCATION_PRIVATE_LOCAL;
1852         char cause_string[256] = "", display[84] = "";
1853
1854         /* check cause parameter */
1855         if ((rparam = routeparam(e_action, PARAM_CAUSE)))
1856         {
1857                 cause = rparam->integer_value;
1858                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'cause' is given: %d\n", ea_endpoint->ep_serial, cause);
1859         }
1860         if ((rparam = routeparam(e_action, PARAM_LOCATION)))
1861         {
1862                 location = rparam->integer_value;
1863                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'location' is given: %d\n", ea_endpoint->ep_serial, location);
1864         }
1865
1866
1867         /* use cause as sample, if not given later */
1868         SPRINT(cause_string, "cause_%02x", cause);
1869
1870         /* check sample parameter */
1871         if ((rparam = routeparam(e_action, PARAM_SAMPLE)))
1872         {
1873                 SCPY(cause_string, rparam->string_value);
1874                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'sample' is given: %s\n", ea_endpoint->ep_serial, cause_string);
1875         }
1876
1877         /* check display */
1878         if ((rparam = routeparam(e_action, PARAM_DISPLAY)))
1879         {
1880                 SCPY(display, rparam->string_value);
1881                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'display' is given: %s\n", ea_endpoint->ep_serial, display);
1882         }
1883
1884         /* disconnect only if connect parameter is not given */
1885         trace_header("ACTION disconnect", DIRECTION_NONE);
1886         add_trace("cause", "value", "%d", cause);
1887         add_trace("cause", "location", "%d", location);
1888         if (cause_string[0])
1889                 add_trace("sample", NULL, "%s", cause_string);
1890         if (display[0])
1891                 add_trace("display", NULL, "%s", display);
1892         end_trace();
1893         new_state(EPOINT_STATE_OUT_DISCONNECT);
1894         set_tone(portlist, cause_string);
1895         if (!(rparam = routeparam(e_action, PARAM_CONNECT)))
1896         {
1897                 message_disconnect_port(portlist, cause, location, display);
1898         } else
1899         {
1900                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1901                 SCPY(message->param.notifyinfo.display, display);
1902                 message_put(message);
1903                 logmessage(message);
1904         }
1905         e_action = NULL;
1906 }
1907
1908
1909 /*
1910  * process dialing help
1911  */
1912 void EndpointAppPBX::action_dialing_help(void)
1913 {
1914         /* show all things that would match */
1915 #if 0
1916         struct numbering *numbering = numbering_int;
1917         char dialing[sizeof(e_dialinginfo.id)];
1918         int i;
1919         struct message *message;
1920         struct route_param *rparam;
1921
1922         /* in case we have no menu (this should never happen) */
1923         if (!numbering)
1924                 return;
1925
1926         /* scroll menu */
1927         if (strchr(e_dialinginfo.id,'*'))
1928         {
1929                 e_menu--;
1930                 e_dialinginfo.id[0] = '\0';
1931         }
1932         if (strchr(e_dialinginfo.id,'#'))
1933         {
1934                 e_menu++;
1935                 e_dialinginfo.id[0] = '\0';
1936         }
1937         
1938         /* get position in menu */
1939         if (e_menu < 0)
1940         {
1941                 /* get last menu position */
1942                 e_menu = 0;
1943                 while(numbering->next)
1944                 {
1945                         e_menu++;
1946                         numbering = numbering->next;
1947                 }
1948         } else
1949         {
1950                 /* get menu position */
1951                 i = 0;
1952                 while(i < e_menu)
1953                 {
1954                         numbering = numbering->next;
1955                         if (!numbering)
1956                         {
1957                                 e_menu = 0;
1958                                 numbering = numbering_int;
1959                                 break;
1960                         }
1961                         i++;
1962                 }
1963         }
1964
1965         /* if we dial something else we need to add the prefix and change the action */
1966         if (e_dialinginfo.id[0])
1967         {
1968                 e_action = NUMB_ACTION_NONE;
1969                 SCPY(dialing, numbering->prefix);
1970                 //we ignore the first digit after selecting
1971                 //SCAT(dialing, e_dialinginfo.id);
1972                 SCPY(e_dialinginfo.id, dialing);
1973                 e_extdialing = e_dialinginfo.id+strlen(numbering->prefix);
1974                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' dialing: %s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], e_dialinginfo.id);
1975 nesting?:
1976                 process_dialing();
1977                 return;
1978         }
1979
1980         /* send display message to port */
1981         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1982         SPRINT(message->param.notifyinfo.display, ">%s %s%s%s", numbering->prefix, numb_actions[numbering->action], (numbering->param[0])?" ":"", numbering->param);
1983         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);
1984         message_put(message);
1985         logmessage(message);
1986 #endif
1987 }
1988
1989
1990 /*
1991  * process dialing deflect
1992  */
1993 void EndpointAppPBX::action_dialing_deflect(void)
1994 {
1995 }
1996
1997
1998 /*
1999  * process dialing setforward
2000  */
2001 void EndpointAppPBX::action_dialing_setforward(void)
2002 {
2003 }
2004
2005
2006 /*
2007  * process hangup 'execute'
2008  */
2009 void EndpointAppPBX::action_hangup_execute(void)
2010 {
2011         struct route_param *rparam;
2012         char *command = "", isdn_port[10];
2013         char *argv[7+1]; /* check also number of args below */
2014         int i = 0;
2015
2016         /* get script / command */
2017         if ((rparam = routeparam(e_action, PARAM_EXECUTE)))
2018                 command = rparam->string_value;
2019         if (command[0] == '\0')
2020         {
2021                 trace_header("ACTION execute (no parameter given)", DIRECTION_NONE);
2022                 end_trace();
2023                 return;
2024         }
2025         trace_header("ACTION execute", DIRECTION_NONE);
2026         add_trace("command", NULL, "%s", command);
2027         end_trace();
2028
2029         argv[0] = command;
2030         while(strchr(argv[0], '/'))
2031                 argv[0] = strchr(argv[0], '/')+1;
2032         if ((rparam = routeparam(e_action, PARAM_PARAM)))
2033         {
2034                 argv[1] = rparam->string_value;
2035                 i++;
2036         }
2037         argv[1+i] = e_extdialing;
2038         argv[2+i] = numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype);
2039         argv[3+i] = e_callerinfo.extension;
2040         argv[4+i] = e_callerinfo.name;
2041         SPRINT(isdn_port, "%d", e_callerinfo.isdn_port);
2042         argv[5+i] = isdn_port;
2043         argv[6+i] = NULL; /* check also number of args above */
2044         execve("/bin/sh", argv, environ);
2045 }
2046
2047
2048 /*
2049  * process hangup 'file'
2050  */
2051 void EndpointAppPBX::action_hangup_file(void)
2052 {
2053         struct route_param *rparam;
2054         char *file, *content, *mode;
2055         FILE *fp;
2056
2057         /* get file / content */
2058         if (!(rparam = routeparam(e_action, PARAM_FILE)))
2059                 file = rparam->string_value;
2060         else
2061                 file = "";
2062         if (!(rparam = routeparam(e_action, PARAM_CONTENT)))
2063                 content = rparam->string_value;
2064         else
2065                 content = e_extdialing;
2066         if (!(rparam = routeparam(e_action, PARAM_APPEND)))
2067                 mode = "a";
2068         else
2069                 mode = "w";
2070         if (file[0] == '\0')
2071         {
2072                 trace_header("ACTION file (no filename given)", DIRECTION_NONE);
2073                 end_trace();
2074                 return;
2075         }
2076         if (!(fp = fopen(file, mode)))
2077         {
2078                 trace_header("ACTION file (failed to open)", DIRECTION_NONE);
2079                 add_trace("file", "name", "%s", file);
2080                 add_trace("file", "mode", "%s", (mode[0]=='w')?"write":"append");
2081                 end_trace();
2082                 return;
2083         }
2084         trace_header("ACTION file", DIRECTION_NONE);
2085         add_trace("file", "name", "%s", file);
2086         add_trace("file", "mode", "%s", (mode[0]=='w')?"write":"append");
2087         add_trace("content", NULL, "%s", content);
2088         end_trace();
2089         fprintf(fp, "%s\n", content);
2090         fclose(fp);
2091 }
2092
2093
2094 /*
2095  * process init 'pick'
2096  */
2097 void EndpointAppPBX::action_init_pick(void)
2098 {
2099         struct route_param *rparam;
2100         char *extensions = NULL;
2101
2102         if ((rparam = routeparam(e_action, PARAM_EXTENSIONS)))
2103                 extensions = rparam->string_value;
2104         
2105         trace_header("ACTION pick", DIRECTION_NONE);
2106         if (extensions) if (extensions[0])
2107                 add_trace("extensions", NULL, "%s", extensions);
2108         end_trace();
2109         pick_call(extensions);
2110 }
2111
2112
2113 /*
2114  * process dialing 'password'
2115  */
2116 void EndpointAppPBX::action_dialing_password(void)
2117 {
2118         struct port_list *portlist = ea_endpoint->ep_portlist;
2119
2120         /* prompt for password */
2121         if (e_extdialing[0] == '\0')
2122         {
2123                 /* give password tone */
2124                 set_tone(portlist, "password");
2125         } else // ELSE!!
2126         if (e_extdialing[1] == '\0')
2127         {
2128                 /* give password tone */
2129                 set_tone(portlist, "dialing");
2130         }
2131
2132         /* wait until all digits are dialed */
2133         if (strlen(e_ext.password) != strlen(e_extdialing))
2134                 return; /* more digits needed */
2135
2136         /* check the password */
2137         if (e_ext.password[0]=='\0' || (strlen(e_ext.password)==strlen(e_extdialing) && !!strcmp(e_ext.password,e_extdialing)))
2138         {
2139                 trace_header("ACTION password_write (wrong password)", DIRECTION_NONE);
2140                 add_trace("dialed", NULL, "%s", e_extdialing);
2141                 end_trace();
2142                 e_connectedmode = 0;
2143                 e_dtmf = 0;
2144                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2145                 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
2146                 set_tone(portlist, "cause_10");
2147                 return;
2148         }
2149
2150         /* write caller id if ACTION_PASSWORD_WRITE was selected */
2151         if (e_action)
2152         if (e_action->index == ACTION_PASSWORD_WRITE)
2153         {
2154                 append_callbackauth(e_ext.number, &e_callbackinfo);
2155                 trace_header("ACTION password_write (written)", DIRECTION_NONE);
2156                 add_trace("dialed", NULL, "%s", e_extdialing);
2157                 end_trace();
2158         }
2159
2160         /* make call state  */
2161         new_state(EPOINT_STATE_IN_OVERLAP);
2162         e_ruleset = ruleset_main;
2163         if (e_ruleset)
2164                 e_rule = e_ruleset->rule_first;
2165         e_action = NULL;
2166         e_dialinginfo.id[0] = '\0';
2167         e_extdialing = e_dialinginfo.id;
2168         set_tone(portlist, "dialpbx");
2169 }
2170
2171 void EndpointAppPBX::action_dialing_password_wr(void)
2172 {
2173         action_dialing_password();
2174 }
2175
2176
2177 /* general process dialing of incoming call
2178  * depending on the detected prefix, subfunctions above (action_*) will be
2179  * calles.
2180  */
2181 void EndpointAppPBX::process_dialing(void)
2182 {
2183         struct port_list *portlist = ea_endpoint->ep_portlist;
2184         struct message *message;
2185         struct route_param *rparam;
2186
2187 //#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.
2188 //PDEBUG(~0, "HANG-BUG-DEBUGGING: entered porcess_dialing\n");
2189         portlist = ea_endpoint->ep_portlist;
2190         /* check if we have a port instance linked to our epoint */
2191         if (!portlist)
2192         {
2193                 portlist_error:
2194                 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);
2195                 e_action_timeout = 0;
2196                 e_match_timeout = 0;
2197                 return;
2198         }
2199         if (portlist->next)
2200         {
2201                 goto portlist_error;
2202         }
2203
2204         /* check nesting levels */
2205         if (++e_rule_nesting > RULE_NESTING)
2206         {
2207                 trace_header("ACTION (nesting too deep)", DIRECTION_NONE);
2208                 add_trace("max-levels", NULL, "%d", RULE_NESTING);
2209                 end_trace();
2210                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2211                 message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
2212                 set_tone(portlist, "cause_3f");
2213                 e_action_timeout = 0;
2214                 e_match_timeout = 0;
2215                 goto end;
2216         }
2217
2218 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before action-timeout processing\n");
2219         /* process timeout */
2220         if (e_action_timeout)
2221         {
2222                 e_action_timeout = 0;
2223                 if (e_state == EPOINT_STATE_CONNECT)
2224                 {
2225                         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);
2226                         goto end;
2227                 }
2228                 if (e_action->index == ACTION_DISCONNECT
2229                  || e_state == EPOINT_STATE_OUT_DISCONNECT)
2230                 {
2231                         /* release after disconnect */
2232                         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2233                         goto end;
2234                 }
2235                 release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, 0);
2236                 e_action = e_action->next;
2237                 if (!e_action)
2238                 {
2239                         /* nothing more, so we release */
2240                         PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, and we have no next action, so we disconnect.\n", ea_endpoint->ep_serial);
2241                         new_state(EPOINT_STATE_OUT_DISCONNECT);
2242                         message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
2243                         set_tone(portlist, "cause_3f");
2244                         goto end;
2245                 }
2246                 goto action_timeout;
2247         }
2248
2249 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before setup/overlap state checking\n");
2250         if (e_state!=EPOINT_STATE_IN_SETUP
2251          && e_state!=EPOINT_STATE_IN_OVERLAP)
2252         {
2253                 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);
2254                 e_match_timeout = 0;
2255                 goto end;
2256         }
2257
2258 #if 0
2259         /* check if we do menu selection */
2260         if (e_action==NUMB_ACTION_NONE && (e_dialinginfo.id[0]=='*' || e_dialinginfo.id[0]=='#'))
2261         /* do menu selection */
2262         if (e_ext.display_menu)
2263         {
2264                 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 */
2265                 {
2266                         e_dialinginfo.id[0] = '\0';
2267                         e_action = NUMB_ACTION_MENU;
2268                         e_menu = 0;
2269                         process_dialing();
2270                         e_match_timeout = 0;
2271                         goto end;
2272                 }
2273                 /* invalid dialing */
2274                 message_disconnect_port(portlist, CAUSE_INCALID, LOCATION_PRIVATE_LOCAL, "");
2275                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
2276                         message->param.disconnectinfo.cause = CAUSE_INVALID;
2277                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2278                                 } else
2279                                 {
2280                                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2281                                         SCPY(message->param.notifyinfo.display,get_isdn_cause(LOCATION_PRIVATE_LOCAL, epoint->e_ext.display_cause, param->disconnectinfo.location, param->disconnectinfo.cause));
2282                                 }
2283                         message_put(message);
2284                         logmessage(message);
2285                 }
2286                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2287                 set_tone(portlist,"cause_1c");
2288                 e_match_timeout = 0;
2289                 goto end;
2290         }
2291 #endif
2292
2293 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before e_action==NULL\n");
2294         /* if no action yet, we will call try to find a matching rule */
2295         if (!e_action)
2296         {
2297                 /* be sure that all selectors are initialized */
2298                 e_select = 0;
2299
2300                 /* check for external call */
2301                 if (!strncmp(e_dialinginfo.id, "extern:", 7))
2302                 {
2303                         e_extdialing = e_dialinginfo.id+7;
2304                         e_action = &action_external;
2305                         goto process_action;
2306                 }
2307                 /* check for internal call */
2308                 if (!strncmp(e_dialinginfo.id, "intern:", 7))
2309                 {
2310                         e_extdialing = e_dialinginfo.id+7;
2311                         e_action = &action_internal;
2312                         goto process_action;
2313                 }
2314                 /* check for chan call */
2315                 if (!strncmp(e_dialinginfo.id, "chan:", 5))
2316                 {
2317                         e_extdialing = e_dialinginfo.id+4;
2318                         e_action = &action_chan;
2319                         goto process_action;
2320                 }
2321                 /* check for vbox call */
2322                 if (!strncmp(e_dialinginfo.id, "vbox:", 5))
2323                 {
2324                         e_extdialing = e_dialinginfo.id+5;
2325                         e_action = &action_vbox;
2326                         goto process_action;
2327                 }
2328
2329                 if (e_match_timeout && now_d>=e_match_timeout)
2330                 {
2331                         /* return timeout rule */
2332                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', timeout in ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name);
2333                         e_match_timeout = 0;
2334                         e_action = e_match_to_action;
2335                         e_extdialing = e_match_to_extdialing;
2336                         trace_header("ROUTING (timeout)", DIRECTION_NONE);
2337                         add_trace("action", NULL, "%s", action_defs[e_action->index].name);
2338                         add_trace("line", NULL, "%d", e_action->line);
2339                         end_trace();
2340                 } else
2341                 {
2342 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before routing\n");
2343                         /* check for matching rule */
2344                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', checking matching rule of ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name);
2345                         if (e_ruleset)
2346                         {
2347                                 e_action = route(e_ruleset);
2348                                 if (e_action)
2349                                 {
2350                                         trace_header("ACTION (match)", DIRECTION_NONE);
2351                                         add_trace("action", NULL, "%s", action_defs[e_action->index].name);
2352                                         add_trace("line", NULL, "%d", e_action->line);
2353                                         end_trace();
2354                                 }
2355                         } else
2356                         {
2357                                 e_action = &action_disconnect;
2358                                 if (e_action)
2359                                 {
2360                                         trace_header("ACTION (no main ruleset, disconnecting)", DIRECTION_NONE);
2361                                         end_trace();
2362                                 }
2363                         }
2364 //PDEBUG(~0, "HANG-BUG-DEBUGGING: after routing\n");
2365                 }
2366                 if (!e_action)
2367                 {
2368                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): no rule within the current ruleset matches yet.\n", ea_endpoint->ep_serial, e_ext.number);
2369                         goto display;
2370                 }
2371
2372                 /* matching */
2373                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): a rule with action '%s' matches.\n", ea_endpoint->ep_serial, action_defs[e_action->index].name);
2374
2375                 action_timeout:
2376
2377                 /* set timeout */
2378                 e_action_timeout = 0;
2379                 if (e_action->timeout)
2380                 {
2381                         e_action_timeout = now_d + e_action->timeout;
2382                         PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action has a timeout of %d secods.\n", ea_endpoint->ep_serial, e_action->timeout);
2383                 }
2384
2385                 process_action:
2386                 /* check param proceeding / alerting / connect */
2387                 if ((rparam = routeparam(e_action, PARAM_CONNECT)))
2388                 {
2389                         /* NOTE: we may not change our state to connect, because dialing will then not possible */
2390                         e_dtmf = 1;
2391                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2392                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2393                         message_put(message);
2394                         logmessage(message);
2395                 } else
2396                 if ((rparam = routeparam(e_action, PARAM_ALERTING)))
2397                 {
2398                         /* NOTE: we may not change our state to alerting, because dialing will then not possible */
2399                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2400                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2401                         message_put(message);
2402                         logmessage(message);
2403                 } else
2404                 if ((rparam = routeparam(e_action, PARAM_PROCEEDING)))
2405                 {
2406                         /* NOTE: we may not change our state to proceeding, because dialing will then not possible */
2407                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2408                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2409                         message_put(message);
2410                         logmessage(message);
2411                 }
2412
2413                 if (action_defs[e_action->index].init_func)
2414                 {
2415                         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);
2416                         (this->*(action_defs[e_action->index].init_func))();
2417                 }
2418                 if (e_state!=EPOINT_STATE_IN_SETUP
2419                  && e_state!=EPOINT_STATE_IN_OVERLAP)
2420                 {
2421                         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);
2422                         goto display_action;
2423                 }
2424         }
2425
2426         /* show what we are doing */
2427         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);
2428         /* go to action's dialing function */
2429         if (action_defs[e_action->index].dialing_func)
2430         {
2431                 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);
2432                 (this->*(action_defs[e_action->index].dialing_func))();
2433         }
2434
2435         /* display selected dialing action if enabled and still in setup state */
2436         display_action:
2437         if (e_action)
2438         {
2439                 if (e_action->index==ACTION_MENU
2440                  || e_action->index==ACTION_REDIAL
2441                  || e_action->index==ACTION_REPLY
2442                  || e_action->index==ACTION_TIMER
2443                  || e_action->index==ACTION_CALCULATOR
2444                  || e_action->index==ACTION_TEST)
2445                         goto end;
2446         }
2447         display:
2448         if (!e_ext.display_dialing)
2449                 goto end;
2450         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*/)
2451         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 */
2452         {
2453                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2454
2455                 if (!e_action)
2456                 {
2457                         SPRINT(message->param.notifyinfo.display, "> %s", e_dialinginfo.id);
2458                 } else
2459                 {
2460                         SPRINT(message->param.notifyinfo.display, "%s%s%s", action_defs[e_action->index].name, (e_extdialing[0])?" ":"", e_extdialing);
2461                 }
2462
2463                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s displaying interpreted dialing '%s'\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
2464                 message_put(message);
2465                 logmessage(message);
2466         }
2467
2468 end:
2469         e_rule_nesting--;
2470         return;
2471 }
2472
2473
2474 /* some services store information after hangup */
2475 void EndpointAppPBX::process_hangup(int cause, int location)
2476 {
2477         char callertext[256], dialingtext[256];
2478         int writeext = 0, i;
2479
2480         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2481         if (e_ext.number[0])
2482         {
2483                 if (read_extension(&e_ext, e_ext.number))
2484                         writeext = 0x10;
2485
2486                 if (!e_start)
2487                 {
2488                         time(&e_start);
2489                         e_stop = 0;
2490                 } else
2491                 if (!e_stop)
2492                         time(&e_stop);
2493                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): writing connect from %s to %s into logfile of %s\n", ea_endpoint->ep_serial, e_callerinfo.id, e_dialinginfo.id, e_ext.number);
2494                 switch(e_dialinginfo.itype)
2495                 {
2496                         case INFO_ITYPE_CHAN:
2497                         SPRINT(dialingtext, "chan:%s", e_dialinginfo.id);
2498                         break;
2499                         case INFO_ITYPE_ISDN_EXTENSION:
2500                         SPRINT(dialingtext, "intern:%s", e_dialinginfo.id);
2501                         break;
2502                         case INFO_ITYPE_VBOX:
2503                         SPRINT(dialingtext, "vbox:%s", e_dialinginfo.id);
2504                         break;
2505                         default:
2506                         SPRINT(dialingtext, "%s", e_dialinginfo.id);
2507                 }
2508
2509                 if (e_callerinfo.id[0])
2510                         SPRINT(callertext, "%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
2511                 else
2512                         SPRINT(callertext, "unknown");
2513                 /* allpy restriction */
2514                 if (!e_ext.anon_ignore && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
2515                         SPRINT(callertext, "anonymous");
2516                 if (e_callerinfo.extension[0]) /* add intern if present */
2517                         UNPRINT(strchr(callertext,'\0'), sizeof(callertext)-1+strlen(callertext), " (intern %s)", e_callerinfo.extension);
2518                 write_log(e_ext.number, callertext, dialingtext, e_start, e_stop, 0, cause, location);
2519
2520                 /* store last received call for reply-list */
2521                 if (e_callerinfo.id[0] || e_callerinfo.extension[0])
2522                 if (e_ext.anon_ignore || e_callerinfo.present!=INFO_PRESENT_RESTRICTED)
2523                 {
2524                         if (e_callerinfo.extension[0])
2525                                 SPRINT(callertext, "intern:%s", e_callerinfo.extension);
2526                         else
2527                                 SPRINT(callertext, "extern:%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
2528                         if (!!strcmp(callertext, e_ext.last_in[0]))
2529                         {
2530                                 i = MAX_REMEMBER-1;
2531                                 while(i)
2532                                 {
2533                                         UCPY(e_ext.last_in[i], e_ext.last_in[i-1]);
2534                                         i--;
2535                                 }
2536                                 SCPY(e_ext.last_in[0], callertext);
2537                                 writeext |= 1; /* store extension later */
2538                                 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]);
2539                         } else
2540                                 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);
2541                 }
2542         }
2543
2544         /* write extension if needed */
2545         if (writeext == 0x11)
2546                 write_extension(&e_ext, e_ext.number);
2547
2548         if (e_action)
2549         {
2550                 if (action_defs[e_action->index].hangup_func)
2551                 {
2552                         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);
2553                         (this->*(action_defs[e_action->index].hangup_func))();
2554                 }
2555         }
2556 }
2557