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