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