92
92
</configObject>
93
93
</configFile>
94
94
</configInfo>
95
+ <function name="WHOZZ_LINE_STATE" language="en_US">
96
+ <synopsis>
97
+ Returns the line state of a WHOZZ Calling? line
98
+ </synopsis>
99
+ <syntax>
100
+ <parameter name="line" required="true">
101
+ <para>Line number</para>
102
+ </parameter>
103
+ </syntax>
104
+ <description>
105
+ <para>Returns the line state of the specified line.</para>
106
+ <para>The possible values are:</para>
107
+ <enumlist>
108
+ <enum name="UNKNOWN"/>
109
+ <enum name="ONHOOK"/>
110
+ <enum name="OFFHOOK"/>
111
+ <enum name="RINGING"/>
112
+ </enumlist>
113
+ </description>
114
+ </function>
95
115
***/
96
116
97
117
#define MODULE_NAME "res_smdr_whozz"
@@ -162,7 +182,7 @@ static int unloading = 0;
162
182
ast_debug (3 , "Received %ld bytes from serial port: %s\n" , bufres , buf ); \
163
183
}
164
184
165
- static const char * state_str (enum line_state state )
185
+ static const char * state_str_cli (enum line_state state )
166
186
{
167
187
switch (state ) {
168
188
case UNKNOWN :
@@ -177,6 +197,21 @@ static const char *state_str(enum line_state state)
177
197
__builtin_unreachable ();
178
198
}
179
199
200
+ static const char * state_str_func (enum line_state state )
201
+ {
202
+ switch (state ) {
203
+ case UNKNOWN :
204
+ return "UNKNOWN" ;
205
+ case ONHOOK :
206
+ return "ONHOOK" ;
207
+ case OFFHOOK :
208
+ return "OFFHOOK" ;
209
+ case RINGING :
210
+ return "RINGING" ;
211
+ }
212
+ __builtin_unreachable ();
213
+ }
214
+
180
215
static int serial_getline (struct pollfd * pfd , int pollfirst , char * restrict buf , size_t len )
181
216
{
182
217
size_t total = 0 ;
@@ -445,8 +480,92 @@ static int handle_hook(struct whozz_line *w, int outbound, int end, int duration
445
480
return -1; \
446
481
}
447
482
483
+ static void update_state (struct whozz_line * w , enum line_state newstate , enum line_state oldstate )
484
+ {
485
+ w -> state = newstate ;
486
+ manager_event (EVENT_FLAG_CALL , "WHOZZLineStateChange" ,
487
+ "LineNumber: %d\r\n"
488
+ "CurrentState: %s\r\n"
489
+ "OldState: %s\r\n" ,
490
+ w -> lineno ,
491
+ state_str_func (w -> state ),
492
+ state_str_func (oldstate ));
493
+ }
494
+
448
495
static int __process_serial_read (struct whozz_line * w , int lineno , const char * action , char * buf , size_t len )
449
496
{
497
+ enum line_state oldstate = w -> state ;
498
+ /*** DOCUMENTATION
499
+ <managerEvent language="en_US" name="WHOZZLineStateChange">
500
+ <managerEventInstance class="EVENT_FLAG_CALL">
501
+ <synopsis>Raised when the state of a phone line connected to
502
+ a WHOZZ Calling? device changes.</synopsis>
503
+ <syntax>
504
+ <channel_snapshot/>
505
+ <parameter name="LineNumber">
506
+ <para>The line number</para>
507
+ </parameter>
508
+ <parameter name="CurrentState">
509
+ <para>The current state of the line.</para>
510
+ <para>The possible values are:</para>
511
+ <enumlist>
512
+ <enum name="UNKNOWN"/>
513
+ <enum name="ONHOOK"/>
514
+ <enum name="OFFHOOK"/>
515
+ <enum name="RINGING"/>
516
+ </enumlist>
517
+ </parameter>
518
+ <parameter name="OldState">
519
+ <para>The old state of the line.</para>
520
+ <para>The possible values are:</para>
521
+ <enumlist>
522
+ <enum name="UNKNOWN"/>
523
+ <enum name="ONHOOK"/>
524
+ <enum name="OFFHOOK"/>
525
+ <enum name="RINGING"/>
526
+ </enumlist>
527
+ </parameter>
528
+ </syntax>
529
+ <description>
530
+ <para>This event is raised whenever the line state of a line changes.</para>
531
+ </description>
532
+ </managerEventInstance>
533
+ </managerEvent>
534
+ <managerEvent language="en_US" name="WHOZZLineCall">
535
+ <managerEventInstance class="EVENT_FLAG_CALL">
536
+ <synopsis>Raised when a call begins or ends on a phone line
537
+ connected to a WHOZZ Calling? device.</synopsis>
538
+ <syntax>
539
+ <channel_snapshot/>
540
+ <parameter name="LineNumber">
541
+ <para>The line number</para>
542
+ </parameter>
543
+ <parameter name="Direction">
544
+ <para>IN or OUT.</para>
545
+ </parameter>
546
+ <parameter name="Duration">
547
+ <para>Call duration, in seconds.</para>
548
+ <para>Only provided when a call ends.</para>
549
+ </parameter>
550
+ <parameter name="CalledNumber">
551
+ <para>The called number.</para>
552
+ <para>Only provided for outgoing calls.</para>
553
+ </parameter>
554
+ <parameter name="CallerNumber">
555
+ <para>The calling number.</para>
556
+ <para>Only provided for incoming calls.</para>
557
+ </parameter>
558
+ <parameter name="CallerName">
559
+ <para>The calling name.</para>
560
+ <para>Only provided for incoming calls.</para>
561
+ </parameter>
562
+ </syntax>
563
+ <description>
564
+ <para>This event is raised whenever the line state of a line changes.</para>
565
+ </description>
566
+ </managerEventInstance>
567
+ </managerEvent>
568
+ ***/
450
569
if (!strcasecmp (action , "F" )) {
451
570
ast_verb (5 , "Off-hook on line %d\n" , lineno );
452
571
if (w -> state == RINGING ) {
@@ -458,13 +577,13 @@ static int __process_serial_read(struct whozz_line *w, int lineno, const char *a
458
577
ast_log (LOG_WARNING , "No call in progress, ignoring call answer\n" );
459
578
}
460
579
}
461
- w -> state = OFFHOOK ;
580
+ update_state ( w , OFFHOOK , oldstate ) ;
462
581
} else if (!strcasecmp (action , "N" )) {
463
582
ast_verb (5 , "On-hook on line %d\n" , lineno );
464
- w -> state = ONHOOK ;
583
+ update_state ( w , ONHOOK , oldstate ) ;
465
584
} else if (!strcasecmp (action , "R" )) {
466
585
ast_verb (5 , "First ring on line %d\n" , lineno );
467
- w -> state = RINGING ;
586
+ update_state ( w , RINGING , oldstate ) ;
468
587
/* This could be followed by I S: Incoming Call Start (whether or not the line has Caller ID, and even if call is answered before first ring ends)
469
588
* That, in turn, is followed by F, for off hook if somebody answers it,
470
589
* or I E (Incoming Call End), if ring no answer. */
@@ -498,11 +617,62 @@ static int __process_serial_read(struct whozz_line *w, int lineno, const char *a
498
617
duration = atoi (durationstr );
499
618
if (callend ) {
500
619
ast_log (LOG_NOTICE , "%s call %s on line %d to %s (%d s)\n" , outbound ? "Outbound" : "Inbound" , "ended" , lineno , numberstr , duration );
620
+ /* If we were previously ringing, and never went off-hook,
621
+ * there won't be an on-hook event that will reset the line state,
622
+ * do it here. */
623
+ if (oldstate == RINGING ) {
624
+ update_state (w , ONHOOK , oldstate );
625
+ }
501
626
} else {
502
627
ast_log (LOG_NOTICE , "%s call %s on line %d to %s\n" , outbound ? "Outbound" : "Inbound" , "began" , lineno , numberstr );
503
628
}
504
629
/* Log/store the appropriate details */
505
630
handle_hook (w , outbound , callend , duration , numberstr , cnam );
631
+ if (callend ) {
632
+ if (outbound ) {
633
+ manager_event (EVENT_FLAG_CALL , "WHOZZLineCall" ,
634
+ "LineNumber: %d\r\n"
635
+ "Direction: %s\r\n"
636
+ "Duration: %d\r\n"
637
+ "CalledNumber: %s\r\n" ,
638
+ w -> lineno ,
639
+ outbound ? "OUT" : "IN" ,
640
+ duration ,
641
+ numberstr );
642
+ } else {
643
+ manager_event (EVENT_FLAG_CALL , "WHOZZLineCall" ,
644
+ "LineNumber: %d\r\n"
645
+ "Direction: %s\r\n"
646
+ "Duration: %d\r\n"
647
+ "CallerNumber: %s\r\n"
648
+ "CallerName: %s\r\n" ,
649
+ w -> lineno ,
650
+ outbound ? "OUT" : "IN" ,
651
+ duration ,
652
+ numberstr ,
653
+ cnam );
654
+ }
655
+ } else {
656
+ if (outbound ) {
657
+ manager_event (EVENT_FLAG_CALL , "WHOZZLineCall" ,
658
+ "LineNumber: %d\r\n"
659
+ "Direction: %s\r\n"
660
+ "CalledNumber: %s\r\n" ,
661
+ w -> lineno ,
662
+ outbound ? "OUT" : "IN" ,
663
+ numberstr );
664
+ } else {
665
+ manager_event (EVENT_FLAG_CALL , "WHOZZLineCall" ,
666
+ "LineNumber: %d\r\n"
667
+ "Direction: %s\r\n"
668
+ "CallerNumber: %s\r\n"
669
+ "CallerName: %s\r\n" ,
670
+ w -> lineno ,
671
+ outbound ? "OUT" : "IN" ,
672
+ numberstr ,
673
+ cnam );
674
+ }
675
+ }
506
676
}
507
677
return 0 ;
508
678
}
@@ -633,6 +803,34 @@ static void *__serial_monitor(void *varg)
633
803
return NULL ;
634
804
}
635
805
806
+ static int whozz_line_state_read (struct ast_channel * chan , const char * cmd , char * parse , char * buffer , size_t buflen )
807
+ {
808
+ int lineno ;
809
+ struct whozz_line * w ;
810
+
811
+ if (ast_strlen_zero (parse )) {
812
+ ast_log (LOG_ERROR , "Line number required for %s\n" , cmd );
813
+ return -1 ;
814
+ }
815
+
816
+ lineno = atoi (parse );
817
+ AST_RWLIST_RDLOCK (& lines );
818
+ AST_RWLIST_TRAVERSE (& lines , w , entry ) {
819
+ if (w -> lineno == lineno ) {
820
+ ast_copy_string (buffer , state_str_func (w -> state ), buflen );
821
+ break ;
822
+ }
823
+ }
824
+ AST_RWLIST_UNLOCK (& lines );
825
+
826
+ return w ? 0 : -1 ;
827
+ }
828
+
829
+ static struct ast_custom_function acf_whozz = {
830
+ .name = "WHOZZ_LINE_STATE" ,
831
+ .read = whozz_line_state_read ,
832
+ };
833
+
636
834
static char * handle_show_whozz (struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
637
835
{
638
836
struct whozz_line * w ;
@@ -655,7 +853,7 @@ static char *handle_show_whozz(struct ast_cli_entry *e, int cmd, struct ast_cli_
655
853
ast_cli (a -> fd , "%4s %-8s %s\n" , "Line" , "State" , "Associated Device" );
656
854
AST_RWLIST_RDLOCK (& lines );
657
855
AST_RWLIST_TRAVERSE (& lines , w , entry ) {
658
- ast_cli (a -> fd , "%4d %-8s %s\n" , w -> lineno , state_str (w -> state ), S_OR (w -> device , "" ));
856
+ ast_cli (a -> fd , "%4d %-8s %s\n" , w -> lineno , state_str_cli (w -> state ), S_OR (w -> device , "" ));
659
857
}
660
858
AST_RWLIST_UNLOCK (& lines );
661
859
@@ -763,6 +961,7 @@ static int unload_module(void)
763
961
764
962
unloading = 1 ;
765
963
ast_cli_unregister_multiple (whozz_cli , ARRAY_LEN (whozz_cli ));
964
+ ast_custom_function_unregister (& acf_whozz );
766
965
if (serial_fd != -1 ) {
767
966
if (serial_thread != AST_PTHREADT_NULL ) {
768
967
/* Interrupt any system call */
@@ -826,6 +1025,7 @@ static int load_module(void)
826
1025
return AST_MODULE_LOAD_DECLINE ;
827
1026
}
828
1027
1028
+ ast_custom_function_register (& acf_whozz );
829
1029
ast_cli_register_multiple (whozz_cli , ARRAY_LEN (whozz_cli ));
830
1030
return res ;
831
1031
}
0 commit comments