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