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