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