Merge branch 'master' of ssh://jolly@www.mISDN.org/var/git/lcr
[lcr.git] / action.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** all actions (and hangup) are processed here                               **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include <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 lcr_msg          *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 lcr_msg          *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 lcr_msg *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 lcr_msg *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 lcr_msg *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 lcr_msg *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 lcr_msg *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, 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 lcr_msg *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 lcr_msg *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 lcr_msg *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, 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 lcr_msg *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         {
1841                 add_trace("dialing", NULL, "%s", e_dialinginfo.id);
1842         }
1843         if ((rparam = routeparam(e_action, PARAM_SAMPLE)))
1844         {
1845                 add_trace("sample", NULL, "%s", rparam->string_value);
1846                 end_trace();
1847                 set_tone(ea_endpoint->ep_portlist, rparam->string_value);
1848         } else
1849         {
1850                 end_trace();
1851         }
1852
1853         /* do dialing with new ruleset */
1854         e_action = NULL;
1855         process_dialing();
1856 }
1857
1858 /* process dialing goto
1859 */
1860 void EndpointAppPBX::action_dialing_goto(void)
1861 {
1862         _action_goto_menu(0);
1863 }
1864
1865 /* process dialing menu
1866 */
1867 void EndpointAppPBX::action_dialing_menu(void)
1868 {
1869         _action_goto_menu(1);
1870 }
1871
1872
1873 /*
1874  * process dialing disconnect
1875  */
1876 void EndpointAppPBX::action_dialing_disconnect(void)
1877 {
1878         struct route_param *rparam;
1879         struct port_list *portlist = ea_endpoint->ep_portlist;
1880         struct lcr_msg *message;
1881         int cause = CAUSE_NORMAL; /* normal call clearing */
1882         int location = LOCATION_PRIVATE_LOCAL;
1883         char cause_string[256] = "", display[84] = "";
1884
1885         /* check cause parameter */
1886         if ((rparam = routeparam(e_action, PARAM_CAUSE)))
1887         {
1888                 cause = rparam->integer_value;
1889                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'cause' is given: %d\n", ea_endpoint->ep_serial, cause);
1890         }
1891         if ((rparam = routeparam(e_action, PARAM_LOCATION)))
1892         {
1893                 location = rparam->integer_value;
1894                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'location' is given: %d\n", ea_endpoint->ep_serial, location);
1895         }
1896
1897
1898         /* use cause as sample, if not given later */
1899         SPRINT(cause_string, "cause_%02x", cause);
1900
1901         /* check sample parameter */
1902         if ((rparam = routeparam(e_action, PARAM_SAMPLE)))
1903         {
1904                 SCPY(cause_string, rparam->string_value);
1905                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'sample' is given: %s\n", ea_endpoint->ep_serial, cause_string);
1906         }
1907
1908         /* check display */
1909         if ((rparam = routeparam(e_action, PARAM_DISPLAY)))
1910         {
1911                 SCPY(display, rparam->string_value);
1912                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'display' is given: %s\n", ea_endpoint->ep_serial, display);
1913         }
1914
1915         /* disconnect only if connect parameter is not given */
1916         trace_header("ACTION disconnect", DIRECTION_NONE);
1917         add_trace("cause", "value", "%d", cause);
1918         add_trace("cause", "location", "%d", location);
1919         if (cause_string[0])
1920                 add_trace("sample", NULL, "%s", cause_string);
1921         if (display[0])
1922                 add_trace("display", NULL, "%s", display);
1923         end_trace();
1924         new_state(EPOINT_STATE_OUT_DISCONNECT);
1925         set_tone(portlist, cause_string);
1926         if (!(rparam = routeparam(e_action, PARAM_CONNECT)))
1927         {
1928                 message_disconnect_port(portlist, cause, location, display);
1929         } else
1930         {
1931                 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1932                 SCPY(message->param.notifyinfo.display, display);
1933                 message_put(message);
1934                 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1935         }
1936         e_action = NULL;
1937 }
1938
1939
1940 /*
1941  * process dialing help
1942  */
1943 void EndpointAppPBX::action_dialing_help(void)
1944 {
1945         /* show all things that would match */
1946 #if 0
1947         struct numbering *numbering = numbering_int;
1948         char dialing[sizeof(e_dialinginfo.id)];
1949         int i;
1950         struct lcr_msg *message;
1951         struct route_param *rparam;
1952
1953         /* in case we have no menu (this should never happen) */
1954         if (!numbering)
1955                 return;
1956
1957         /* scroll menu */
1958         if (strchr(e_dialinginfo.id,'*'))
1959         {
1960                 e_menu--;
1961                 e_dialinginfo.id[0] = '\0';
1962         }
1963         if (strchr(e_dialinginfo.id,'#'))
1964         {
1965                 e_menu++;
1966                 e_dialinginfo.id[0] = '\0';
1967         }
1968         
1969         /* get position in menu */
1970         if (e_menu < 0)
1971         {
1972                 /* get last menu position */
1973                 e_menu = 0;
1974                 while(numbering->next)
1975                 {
1976                         e_menu++;
1977                         numbering = numbering->next;
1978                 }
1979         } else
1980         {
1981                 /* get menu position */
1982                 i = 0;
1983                 while(i < e_menu)
1984                 {
1985                         numbering = numbering->next;
1986                         if (!numbering)
1987                         {
1988                                 e_menu = 0;
1989                                 numbering = numbering_int;
1990                                 break;
1991                         }
1992                         i++;
1993                 }
1994         }
1995
1996         /* if we dial something else we need to add the prefix and change the action */
1997         if (e_dialinginfo.id[0])
1998         {
1999                 e_action = NUMB_ACTION_NONE;
2000                 SCPY(dialing, numbering->prefix);
2001                 //we ignore the first digit after selecting
2002                 //SCAT(dialing, e_dialinginfo.id);
2003                 SCPY(e_dialinginfo.id, dialing);
2004                 e_extdialing = e_dialinginfo.id+strlen(numbering->prefix);
2005                 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);
2006 nesting?:
2007                 process_dialing();
2008                 return;
2009         }
2010
2011         /* send display message to port */
2012         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2013         SPRINT(message->param.notifyinfo.display, ">%s %s%s%s", numbering->prefix, numb_actions[numbering->action], (numbering->param[0])?" ":"", numbering->param);
2014         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);
2015         message_put(message);
2016         logmessage(message->type, message->paramea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2017 #endif
2018 }
2019
2020
2021 /*
2022  * process dialing deflect
2023  */
2024 void EndpointAppPBX::action_dialing_deflect(void)
2025 {
2026 }
2027
2028
2029 /*
2030  * process dialing setforward
2031  */
2032 void EndpointAppPBX::action_dialing_setforward(void)
2033 {
2034 }
2035
2036
2037 /*
2038  * process hangup 'execute'
2039  */
2040 void EndpointAppPBX::action_hangup_execute(void)
2041 {
2042         struct route_param *rparam;
2043         pid_t pid;
2044         char *command = "", isdn_port[10];
2045         char *argv[11]; /* check also number of args below */
2046         int i = 0;
2047
2048         /* get script / command */
2049         if ((rparam = routeparam(e_action, PARAM_EXECUTE)))
2050                 command = rparam->string_value;
2051         if (command[0] == '\0')
2052         {
2053                 trace_header("ACTION execute (no parameter given)", DIRECTION_NONE);
2054                 end_trace();
2055                 return;
2056         }
2057         argv[i++] = "/bin/sh";
2058         argv[i++] = "-c";
2059         argv[i++] = command;
2060         argv[i++] = command;
2061         if ((rparam = routeparam(e_action, PARAM_PARAM)))
2062         {
2063                 argv[i++] = rparam->string_value;
2064         }
2065         argv[i++] = e_extdialing;
2066         argv[i++] = numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype);
2067         argv[i++] = e_callerinfo.extension;
2068         argv[i++] = e_callerinfo.name;
2069         SPRINT(isdn_port, "%d", e_callerinfo.isdn_port);
2070         argv[i++] = isdn_port;
2071         argv[i++] = NULL; /* check also number of args above */
2072         switch (pid = fork ()) {
2073                 case -1:
2074                         trace_header("ACTION execute (fork failed)", DIRECTION_NONE);
2075                         end_trace();
2076                         break;
2077                 case 0:
2078                         execve("/bin/sh", argv, environ);
2079                         break;
2080                 default:
2081                         trace_header("ACTION execute", DIRECTION_NONE);
2082                         add_trace("command", NULL, "%s", command);
2083                         end_trace();
2084                         break;
2085         }
2086 }
2087
2088
2089 /*
2090  * process hangup 'file'
2091  */
2092 void EndpointAppPBX::action_hangup_file(void)
2093 {
2094         struct route_param *rparam;
2095         char *file, *content, *mode;
2096         FILE *fp;
2097
2098         /* get file / content */
2099         if (!(rparam = routeparam(e_action, PARAM_FILE)))
2100                 file = rparam->string_value;
2101         else
2102                 file = "";
2103         if (!(rparam = routeparam(e_action, PARAM_CONTENT)))
2104                 content = rparam->string_value;
2105         else
2106                 content = e_extdialing;
2107         if (!(rparam = routeparam(e_action, PARAM_APPEND)))
2108                 mode = "a";
2109         else
2110                 mode = "w";
2111         if (file[0] == '\0')
2112         {
2113                 trace_header("ACTION file (no filename given)", DIRECTION_NONE);
2114                 end_trace();
2115                 return;
2116         }
2117         if (!(fp = fopen(file, mode)))
2118         {
2119                 trace_header("ACTION file (failed to open)", DIRECTION_NONE);
2120                 add_trace("file", "name", "%s", file);
2121                 add_trace("file", "mode", "%s", (mode[0]=='w')?"write":"append");
2122                 end_trace();
2123                 return;
2124         }
2125         trace_header("ACTION file", DIRECTION_NONE);
2126         add_trace("file", "name", "%s", file);
2127         add_trace("file", "mode", "%s", (mode[0]=='w')?"write":"append");
2128         add_trace("content", NULL, "%s", content);
2129         end_trace();
2130         fprintf(fp, "%s\n", content);
2131         fclose(fp);
2132 }
2133
2134
2135 /*
2136  * process init 'pick'
2137  */
2138 void EndpointAppPBX::action_init_pick(void)
2139 {
2140         struct route_param *rparam;
2141         char *extensions = NULL;
2142
2143         if ((rparam = routeparam(e_action, PARAM_EXTENSIONS)))
2144                 extensions = rparam->string_value;
2145         
2146         trace_header("ACTION pick", DIRECTION_NONE);
2147         if (extensions) if (extensions[0])
2148                 add_trace("extensions", NULL, "%s", extensions);
2149         end_trace();
2150         pick_join(extensions);
2151 }
2152
2153
2154 /*
2155  * process dialing 'password'
2156  */
2157 void EndpointAppPBX::action_dialing_password(void)
2158 {
2159         struct port_list *portlist = ea_endpoint->ep_portlist;
2160
2161         /* prompt for password */
2162         if (e_extdialing[0] == '\0')
2163         {
2164                 /* give password tone */
2165                 set_tone(portlist, "password");
2166         } else // ELSE!!
2167         if (e_extdialing[1] == '\0')
2168         {
2169                 /* give password tone */
2170                 set_tone(portlist, "dialing");
2171         }
2172
2173         /* wait until all digits are dialed */
2174         if (strlen(e_ext.password) != strlen(e_extdialing))
2175                 return; /* more digits needed */
2176
2177         /* check the password */
2178         if (e_ext.password[0]=='\0' || (strlen(e_ext.password)==strlen(e_extdialing) && !!strcmp(e_ext.password,e_extdialing)))
2179         {
2180                 trace_header("ACTION password_write (wrong password)", DIRECTION_NONE);
2181                 add_trace("dialed", NULL, "%s", e_extdialing);
2182                 end_trace();
2183                 e_connectedmode = 0;
2184                 e_dtmf = 0;
2185                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2186                 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
2187                 set_tone(portlist, "cause_10");
2188                 return;
2189         }
2190
2191         /* write caller id if ACTION_PASSWORD_WRITE was selected */
2192         if (e_action)
2193         if (e_action->index == ACTION_PASSWORD_WRITE)
2194         {
2195                 append_callbackauth(e_ext.number, &e_callbackinfo);
2196                 trace_header("ACTION password_write (written)", DIRECTION_NONE);
2197                 add_trace("dialed", NULL, "%s", e_extdialing);
2198                 end_trace();
2199         }
2200
2201         /* make call state  */
2202         new_state(EPOINT_STATE_IN_OVERLAP);
2203         e_ruleset = ruleset_main;
2204         if (e_ruleset)
2205                 e_rule = e_ruleset->rule_first;
2206         e_action = NULL;
2207         e_dialinginfo.id[0] = '\0';
2208         e_extdialing = e_dialinginfo.id;
2209         set_tone(portlist, "dialpbx");
2210 }
2211
2212 void EndpointAppPBX::action_dialing_password_wr(void)
2213 {
2214         action_dialing_password();
2215 }
2216
2217
2218 /* general process dialing of incoming call
2219  * depending on the detected prefix, subfunctions above (action_*) will be
2220  * calles.
2221  */
2222 void EndpointAppPBX::process_dialing(void)
2223 {
2224         struct port_list *portlist = ea_endpoint->ep_portlist;
2225         struct lcr_msg *message;
2226         struct route_param *rparam;
2227
2228 //#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.
2229 //PDEBUG(~0, "HANG-BUG-DEBUGGING: entered porcess_dialing\n");
2230         portlist = ea_endpoint->ep_portlist;
2231         /* check if we have a port instance linked to our epoint */
2232         if (!portlist)
2233         {
2234                 portlist_error:
2235                 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);
2236                 e_action_timeout = 0;
2237                 e_match_timeout = 0;
2238                 return;
2239         }
2240         if (portlist->next)
2241         {
2242                 goto portlist_error;
2243         }
2244
2245         /* check nesting levels */
2246         if (++e_rule_nesting > RULE_NESTING)
2247         {
2248                 trace_header("ACTION (nesting too deep)", DIRECTION_NONE);
2249                 add_trace("max-levels", NULL, "%d", RULE_NESTING);
2250                 end_trace();
2251                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2252                 message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
2253                 set_tone(portlist, "cause_3f");
2254                 e_action_timeout = 0;
2255                 e_match_timeout = 0;
2256                 goto end;
2257         }
2258
2259 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before action-timeout processing\n");
2260         /* process timeout */
2261         if (e_action_timeout)
2262         {
2263                 e_action_timeout = 0;
2264                 if (e_state == EPOINT_STATE_CONNECT)
2265                 {
2266                         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);
2267                         goto end;
2268                 }
2269                 if (e_action->index == ACTION_DISCONNECT
2270                  || e_state == EPOINT_STATE_OUT_DISCONNECT)
2271                 {
2272                         /* release after disconnect */
2273                         release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2274                         goto end;
2275                 }
2276                 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0);
2277                 e_action = e_action->next;
2278                 if (!e_action)
2279                 {
2280                         /* nothing more, so we release */
2281                         PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, and we have no next action, so we disconnect.\n", ea_endpoint->ep_serial);
2282                         new_state(EPOINT_STATE_OUT_DISCONNECT);
2283                         message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
2284                         set_tone(portlist, "cause_3f");
2285                         goto end;
2286                 }
2287                 goto action_timeout;
2288         }
2289
2290 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before setup/overlap state checking\n");
2291         if (e_state!=EPOINT_STATE_IN_SETUP
2292          && e_state!=EPOINT_STATE_IN_OVERLAP)
2293         {
2294                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): we are not in incoming setup/overlap state, so we ignore init/dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
2295                 e_match_timeout = 0;
2296                 goto end;
2297         }
2298
2299 #if 0
2300         /* check if we do menu selection */
2301         if (e_action==NUMB_ACTION_NONE && (e_dialinginfo.id[0]=='*' || e_dialinginfo.id[0]=='#'))
2302         /* do menu selection */
2303         if (e_ext.display_menu)
2304         {
2305                 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 */
2306                 {
2307                         e_dialinginfo.id[0] = '\0';
2308                         e_action = NUMB_ACTION_MENU;
2309                         e_menu = 0;
2310                         process_dialing();
2311                         e_match_timeout = 0;
2312                         goto end;
2313                 }
2314                 /* invalid dialing */
2315                 message_disconnect_port(portlist, CAUSE_INCALID, LOCATION_PRIVATE_LOCAL, "");
2316                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
2317                         message->param.disconnectinfo.cause = CAUSE_INVALID;
2318                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2319                                 } else
2320                                 {
2321                                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2322                                         SCPY(message->param.notifyinfo.display,get_isdn_cause(LOCATION_PRIVATE_LOCAL, epoint->e_ext.display_cause, param->disconnectinfo.location, param->disconnectinfo.cause));
2323                                 }
2324                         message_put(message);
2325                         logmessage(message->type, message->param, portlist->port_id, DIRECTION_OUT);
2326                 }
2327                 new_state(EPOINT_STATE_OUT_DISCONNECT);
2328                 set_tone(portlist,"cause_1c");
2329                 e_match_timeout = 0;
2330                 goto end;
2331         }
2332 #endif
2333
2334 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before e_action==NULL\n");
2335         /* if no action yet, we will call try to find a matching rule */
2336         if (!e_action)
2337         {
2338                 /* be sure that all selectors are initialized */
2339                 e_select = 0;
2340
2341                 /* check for external call */
2342                 if (!strncmp(e_dialinginfo.id, "extern:", 7))
2343                 {
2344                         e_extdialing = e_dialinginfo.id+7;
2345                         e_action = &action_external;
2346                         goto process_action;
2347                 }
2348                 /* check for internal call */
2349                 if (!strncmp(e_dialinginfo.id, "intern:", 7))
2350                 {
2351                         e_extdialing = e_dialinginfo.id+7;
2352                         e_action = &action_internal;
2353                         goto process_action;
2354                 }
2355                 /* check for chan call */
2356                 if (!strncmp(e_dialinginfo.id, "remote:", 7))
2357                 {
2358                         e_extdialing = e_dialinginfo.id+7;
2359                         e_action = &action_remote;
2360                         goto process_action;
2361                 }
2362                 /* check for vbox call */
2363                 if (!strncmp(e_dialinginfo.id, "vbox:", 5))
2364                 {
2365                         e_extdialing = e_dialinginfo.id+5;
2366                         e_action = &action_vbox;
2367                         goto process_action;
2368                 }
2369
2370                 if (e_match_timeout && now_d>=e_match_timeout)
2371                 {
2372                         /* return timeout rule */
2373                         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);
2374                         e_match_timeout = 0;
2375                         e_action = e_match_to_action;
2376                         e_extdialing = e_match_to_extdialing;
2377                         trace_header("ROUTING (timeout)", DIRECTION_NONE);
2378                         add_trace("action", NULL, "%s", action_defs[e_action->index].name);
2379                         add_trace("line", NULL, "%d", e_action->line);
2380                         end_trace();
2381                 } else
2382                 {
2383 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before routing\n");
2384                         /* check for matching rule */
2385                         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);
2386                         if (e_ruleset)
2387                         {
2388                                 e_action = route(e_ruleset);
2389                                 if (e_action)
2390                                 {
2391                                         trace_header("ACTION (match)", DIRECTION_NONE);
2392                                         add_trace("action", NULL, "%s", action_defs[e_action->index].name);
2393                                         add_trace("line", NULL, "%d", e_action->line);
2394                                         end_trace();
2395                                 }
2396                         } else
2397                         {
2398                                 e_action = &action_disconnect;
2399                                 if (e_action)
2400                                 {
2401                                         trace_header("ACTION (no main ruleset, disconnecting)", DIRECTION_NONE);
2402                                         end_trace();
2403                                 }
2404                         }
2405 //PDEBUG(~0, "HANG-BUG-DEBUGGING: after routing\n");
2406                 }
2407                 if (!e_action)
2408                 {
2409                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): no rule within the current ruleset matches yet.\n", ea_endpoint->ep_serial, e_ext.number);
2410                         goto display;
2411                 }
2412
2413                 /* matching */
2414                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): a rule with action '%s' matches.\n", ea_endpoint->ep_serial, action_defs[e_action->index].name);
2415
2416                 action_timeout:
2417
2418                 /* set timeout */
2419                 e_action_timeout = 0;
2420                 if (e_action->timeout)
2421                 {
2422                         e_action_timeout = now_d + e_action->timeout;
2423                         PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action has a timeout of %d secods.\n", ea_endpoint->ep_serial, e_action->timeout);
2424                 }
2425
2426                 process_action:
2427                 /* check param proceeding / alerting / connect */
2428                 if ((rparam = routeparam(e_action, PARAM_CONNECT)))
2429                 {
2430                         /* NOTE: we may not change our state to connect, because dialing will then not possible */
2431                         e_dtmf = 1;
2432                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2433                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2434                         message_put(message);
2435                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2436                 } else
2437                 if ((rparam = routeparam(e_action, PARAM_ALERTING)))
2438                 {
2439                         /* NOTE: we may not change our state to alerting, because dialing will then not possible */
2440                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2441                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2442                         message_put(message);
2443                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2444                 } else
2445                 if ((rparam = routeparam(e_action, PARAM_PROCEEDING)))
2446                 {
2447                         /* NOTE: we may not change our state to proceeding, because dialing will then not possible */
2448                         memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2449                         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2450                         message_put(message);
2451                         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2452                 }
2453
2454                 if (action_defs[e_action->index].init_func)
2455                 {
2456                         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);
2457                         (this->*(action_defs[e_action->index].init_func))();
2458                 }
2459                 if (e_state!=EPOINT_STATE_IN_SETUP
2460                  && e_state!=EPOINT_STATE_IN_OVERLAP)
2461                 {
2462                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): AFTER init process: we are not in incoming setup/overlap state anymore, so we ignore further dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
2463                         goto display_action;
2464                 }
2465         }
2466
2467         /* show what we are doing */
2468         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);
2469         /* go to action's dialing function */
2470         if (action_defs[e_action->index].dialing_func)
2471         {
2472                 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);
2473                 (this->*(action_defs[e_action->index].dialing_func))();
2474         }
2475
2476         /* display selected dialing action if enabled and still in setup state */
2477         display_action:
2478         if (e_action)
2479         {
2480                 if (e_action->index==ACTION_MENU
2481                  || e_action->index==ACTION_REDIAL
2482                  || e_action->index==ACTION_REPLY
2483                  || e_action->index==ACTION_TIMER
2484                  || e_action->index==ACTION_CALCULATOR
2485                  || e_action->index==ACTION_TEST)
2486                         goto end;
2487         }
2488         display:
2489         if (!e_ext.display_dialing)
2490                 goto end;
2491         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*/)
2492         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 */
2493         {
2494                 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2495
2496                 if (!e_action)
2497                 {
2498                         SPRINT(message->param.notifyinfo.display, "> %s", e_dialinginfo.id);
2499                 } else
2500                 {
2501                         SPRINT(message->param.notifyinfo.display, "%s%s%s", action_defs[e_action->index].name, (e_extdialing[0])?" ":"", e_extdialing);
2502                 }
2503
2504                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s displaying interpreted dialing '%s'\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
2505                 message_put(message);
2506                 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2507         }
2508
2509 end:
2510         e_rule_nesting--;
2511         return;
2512 }
2513
2514
2515 /* some services store information after hangup */
2516 void EndpointAppPBX::process_hangup(int cause, int location)
2517 {
2518         char callertext[256], dialingtext[256];
2519         int writeext = 0, i;
2520
2521         PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2522         if (e_ext.number[0])
2523         {
2524                 if (read_extension(&e_ext, e_ext.number))
2525                         writeext = 0x10;
2526
2527                 if (!e_start)
2528                 {
2529                         time(&e_start);
2530                         e_stop = 0;
2531                 } else
2532                 if (!e_stop)
2533                         time(&e_stop);
2534                 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);
2535                 switch(e_dialinginfo.itype)
2536                 {
2537                         case INFO_ITYPE_CHAN:
2538                         SPRINT(dialingtext, "chan:%s", e_dialinginfo.id);
2539                         break;
2540                         case INFO_ITYPE_ISDN_EXTENSION:
2541                         SPRINT(dialingtext, "intern:%s", e_dialinginfo.id);
2542                         break;
2543                         case INFO_ITYPE_VBOX:
2544                         SPRINT(dialingtext, "vbox:%s", e_dialinginfo.id);
2545                         break;
2546                         default:
2547                         SPRINT(dialingtext, "%s", e_dialinginfo.id);
2548                 }
2549
2550                 if (e_callerinfo.id[0])
2551                         SPRINT(callertext, "%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
2552                 else
2553                         SPRINT(callertext, "unknown");
2554                 /* allpy restriction */
2555                 if (!e_ext.anon_ignore && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
2556                         SPRINT(callertext, "anonymous");
2557                 if (e_callerinfo.extension[0]) /* add intern if present */
2558                         UNPRINT(strchr(callertext,'\0'), sizeof(callertext)-1+strlen(callertext), " (intern %s)", e_callerinfo.extension);
2559                 write_log(e_ext.number, callertext, dialingtext, e_start, e_stop, 0, cause, location);
2560
2561                 /* store last received call for reply-list */
2562                 if (e_origin == 1) // outgoing to phone is incoming for user
2563                 if (e_callerinfo.id[0] || e_callerinfo.extension[0])
2564                 if (e_ext.anon_ignore || e_callerinfo.present!=INFO_PRESENT_RESTRICTED)
2565                 {
2566                         if (e_callerinfo.extension[0])
2567                                 SPRINT(callertext, "intern:%s", e_callerinfo.extension);
2568                         else
2569                                 SPRINT(callertext, "extern:%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
2570                         if (!!strcmp(callertext, e_ext.last_in[0]))
2571                         {
2572                                 i = MAX_REMEMBER-1;
2573                                 while(i)
2574                                 {
2575                                         UCPY(e_ext.last_in[i], e_ext.last_in[i-1]);
2576                                         i--;
2577                                 }
2578                                 SCPY(e_ext.last_in[0], callertext);
2579                                 writeext |= 1; /* store extension later */
2580                                 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]);
2581                         } else
2582                                 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);
2583                 }
2584
2585                 /* store last made call for reply-list */
2586                 if (e_origin == 0) // incoming from phone is outgoing for user
2587                 if (e_dialinginfo.id[0])
2588                 {
2589                         if (!!strcmp(e_dialinginfo.id, e_ext.last_out[0]))
2590                         {
2591                                 i = MAX_REMEMBER-1;
2592                                 while(i)
2593                                 {
2594                                         UCPY(e_ext.last_out[i], e_ext.last_out[i-1]);
2595                                         i--;
2596                                 }
2597                                 SCPY(e_ext.last_out[0], e_dialinginfo.id);
2598                                 writeext |= 1; /* store extension later */
2599                                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing last number '%s'.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
2600                         } else
2601                                 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);
2602                 }
2603         }
2604         /* write extension if needed */
2605         if (writeext == 0x11)
2606                 write_extension(&e_ext, e_ext.number);
2607
2608         if (e_action)
2609         {
2610                 if (action_defs[e_action->index].hangup_func)
2611                 {
2612                         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);
2613                         (this->*(action_defs[e_action->index].hangup_func))();
2614                 }
2615         }
2616 }
2617