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