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