File: unsucces.c

package info (click to toggle)
mwavem 2.0-3
  • links: PTS
  • area: non-free
  • in suites: lenny
  • size: 7,188 kB
  • ctags: 6,080
  • sloc: ansic: 52,005; sh: 4,194; makefile: 334
file content (826 lines) | stat: -rw-r--r-- 32,538 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
/*
 *   unsucces.c
 *
 *  Written By: Mike Sullivan IBM Corporation
 *
 *  Copyright (C) 1999 IBM Corporation
 *
 * This program is free software; you can redistribute it and/or modify      
 * it under the terms of the GNU General Public License as published by      
 * the Free Software Foundation; either version 2 of the License, or         
 * (at your option) any later version.                                       
 *                                                                           
 * This program is distributed in the hope that it will be useful,           
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             
 * GNU General Public License for more details.                              
 *                                                                           
 * NO WARRANTY                                                               
 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        
 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      
 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    
 * solely responsible for determining the appropriateness of using and       
 * distributing the Program and assumes all risks associated with its        
 * exercise of rights under this Agreement, including but not limited to     
 * the risks and costs of program errors, damage to or loss of data,         
 * programs or equipment, and unavailability or interruption of operations.  
 *                                                                           
 * DISCLAIMER OF LIABILITY                                                   
 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        
 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    
 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  
 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             
 *                                                                           
 * You should have received a copy of the GNU General Public License         
 * along with this program; if not, write to the Free Software               
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 *                                                         
 *   blwtt.h
 *
 *  Written By: Mike Sullivan IBM Corporation
 *
 *  Copyright (C) 1999 IBM Corporation
 *
 * This program is free software; you can redistribute it and/or modify      
 * it under the terms of the GNU General Public License as published by      
 * the Free Software Foundation; either version 2 of the License, or         
 * (at your option) any later version.                                       
 *                                                                           
 * This program is distributed in the hope that it will be useful,           
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             
 * GNU General Public License for more details.                              
 *                                                                           
 * NO WARRANTY                                                               
 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        
 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      
 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    
 * solely responsible for determining the appropriateness of using and       
 * distributing the Program and assumes all risks associated with its        
 * exercise of rights under this Agreement, including but not limited to     
 * the risks and costs of program errors, damage to or loss of data,         
 * programs or equipment, and unavailability or interruption of operations.  
 *                                                                           
 * DISCLAIMER OF LIABILITY                                                   
 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        
 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    
 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  
 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             
 *                                                                           
 * You should have received a copy of the GNU General Public License         
 * along with this program; if not, write to the Free Software               
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 *                                                                           
 * 
 *  10/23/2000 - Alpha Release 0.1.0
 *            First release to the public
 *
 */
//  This class handles the basic information needed to track call failures
//  for one phone number for one calling device.  This is the most basic
//  object used in the blacklist algorithm.  An overview of operations
//  can be found in the mwbl.txt file.
//
//
//
//****************************************************************************
#include <unsucces.h>  // Header file for this class
#include <blobject.h>  // The WTT settings are imbeded in the main object
#include <string.h>
#include <mwwttbl.h>   // For WT_COUNTRY_CANADA
#include <stdio.h>

extern BLobject BL; //reference the main object which includes the WTTsettings

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  Reset
//
//     This function is used to reset the memory for an UnsuccessfulRecord.
//
//
//     Params:   none
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from mwblapi.h
//
//-----------------------------------------------------------------------------
ULONG failReset (UnsuccessfulRecord *pRec)
{
  USHORT usTimeIndex;

  // Clear the initialized flag
  pRec->bInitialized = FALSE;

  // Clear the phone number
  pRec->szPhoneNumber[0] = '\0';

  // Clear the record status
  pRec->ulRecordStatus = 0;

  // Clear the unsuccessful count
  pRec->ulUnsuccessfulCount = 0;

  // Clear the Non Busy unsuccessful count used for Canada
  pRec->ulNonBusyUnsuccessfulCount = 0;

  // Clear out the timestamps
  for (usTimeIndex = 0; usTimeIndex < MAX_TIME_STAMP_COUNT; usTimeIndex++)
  {
    pRec->TimeStampArray[usTimeIndex] = 0;
  }

  // Set the initialized flag
  pRec->bInitialized = TRUE;

  return BL_SUCCESSFUL;

} //end Reset


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  FindLatestTimeStamp
//
//     This function searches the TimeStamp array for the latest time.  For
//     series type blacklisting this should be the first element.  For time
//     windowing, this is the last non-zero time stamp.
//
//     Params:   none
//
//
//     Returns:  time_t Latest time stamp
//
//-----------------------------------------------------------------------------
time_t failFindLatestTimeStamp(UnsuccessfulRecord *pRec)
{
  USHORT usIndex;  // the compiler expects 16 bits

  //---------------------------------------------------------------------------
  // Class overhead checking
  if (!pRec->bInitialized)
    return (time_t) 0; //return a bogus time
  //---------------------------------------------------------------------------
  
  for (usIndex = 0; usIndex < (MAX_TIME_STAMP_COUNT - 1); usIndex++) {
    if (pRec->TimeStampArray[usIndex+1] == 0 )
      return pRec->TimeStampArray[usIndex];
  }

  // If we came this far then the time stamp array must be full so we will
  // return the last item.
  return pRec->TimeStampArray[ MAX_TIME_STAMP_COUNT - 1 ];
} //end FindLatestTimeStamp


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  IsPhoneNumber
//
//     This function compares a given phone number to the one stored in this
//     UnsuccessfulRecord instance.
//
//     Params:   szComparePhoneNumber - the phone number to test
//
//
//     Returns:  BOOL  Successful:  TRUE
//                     Miscompare:  FALSE
//                     Error:       FALSE
//
//-----------------------------------------------------------------------------
BOOL failIsPhoneNumber (UnsuccessfulRecord *pRec, const char *szComparePhoneNumber)
{
  if (!pRec->bInitialized)
    return FALSE; 
  
  return !strcmp (pRec->szPhoneNumber, szComparePhoneNumber);
} 


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  MakeNewRecord
//
//     This function deletes the current settings and assigns a new
//     szPhoneNumber.  ulRecordStatus becomes FIRST_SERIES.
//
//     Params:   szNewPhoneNumber  - the phone number to save
//
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from mwblapi.h
//
//-----------------------------------------------------------------------------
ULONG failMakeNewRecord (UnsuccessfulRecord *pRec, char *szNewPhoneNumber)
{
  ULONG ulError;

  MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failMakeNewRecord, entry for phone number %s\n", szNewPhoneNumber);
  
  if (!pRec->bInitialized)
    return BLERR_INIT_FAILED + 1000;

  // Is the string too large?
  if (strlen(szNewPhoneNumber) >= MAX_BL_DIAL_STRING) {
    MW_SYSLOG_1(TRACE_MWMBL,"unsucces::failMakeNewRecord, ERROR szNewPhoneNumber is too large\n");
    return BLERR_DIAL_STRING_TOO_LARGE;
  }
  
  // First we need to clean up
  ulError=failReset(pRec);
  if (ulError) {
    MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failMakeNewRecord, ERROR call to faileReset returned ulError %lx\n", ulError);
    return ulError;
  }
  
  
  // Next we need to assign the phone number
  strcpy (pRec->szPhoneNumber, szNewPhoneNumber);


  // The record status will start at First Series, this is correct even if
  // time windowing type of blacklisting is in effect.
  pRec->ulRecordStatus = FIRST_SERIES;

  return BL_SUCCESSFUL;

} // end MakeNewRecord




//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  RequestDialPermission
//
//     This function is used to request permission to dial.  Permission is
//     granted if BL_DIAL_GRANTED is returned.
//
//
//     Params:   CurrentTime    - The current time to check delays against.
//               lpulDialStatus - A pointer to return the status of the request:
//                                BL_DIAL_GRANTED       - OK to dial
//                                BL_NUMBER_BLACKLISTED - permission denied
//                                BL_NUMBER_DELAYED     - permission denied for
//                                                        lpulDelayTime more seconds
//               lpulDelayTime  - A pointer to the returned delay time in seconds.
//
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from the list in mwblapi.h
//
//-----------------------------------------------------------------------------
ULONG failRequestDialPermission (UnsuccessfulRecord *pRec, time_t CurrentTime,
				 ULONG FAR *lpulDialStatus,
				 ULONG FAR *lpulDelayTime)
     
{
  ULONG ulError;

  MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failRequestDialPermission pRec %p\n",pRec);
  MW_SYSLOG_2(TRACE_MWMBL,"  bInitialized %x\n",pRec->bInitialized);
  MW_SYSLOG_2(TRACE_MWMBL,"  szPhoneNumber %s\n",pRec->szPhoneNumber);
  MW_SYSLOG_2(TRACE_MWMBL,"  ulRecordStatus %lx\n",pRec->ulRecordStatus);
  MW_SYSLOG_2(TRACE_MWMBL,"  ulUnsuccessfulCount %lx\n",pRec->ulUnsuccessfulCount);
  MW_SYSLOG_2(TRACE_MWMBL,"  ulNonBusyUnscessfulCount %lx\n",pRec->ulNonBusyUnsuccessfulCount);
  MW_SYSLOG_7(TRACE_MWMBL,"  %lx,%lx,%lx,%lx,%lx,%lx\n",pRec->TimeStampArray[0],
	      pRec->TimeStampArray[1],     
	      pRec->TimeStampArray[2],
	      pRec->TimeStampArray[3],
	      pRec->TimeStampArray[4],
	      pRec->TimeStampArray[5]);
  
  if (!pRec->bInitialized)
    return BLERR_INIT_FAILED + 1100;

  // Check to make sure the number is valid
  if (pRec->szPhoneNumber[0] == '\0')
    return BLERR_PHONE_NUMBER_IS_BLANK;
  
  
  // If the dial handle specified is blacklisted then fail the call.
  if (pRec->ulRecordStatus == NUMBER_BLACKLISTED) {
    *lpulDialStatus = BL_NUMBER_BLACKLISTED;
    return BL_SUCCESSFUL;
  }

  // If this is a call window algorithm, clean out old time stamps and see
  // if we can dial.  CheckCallWindow also sets the dial status and delay time.
  if (BL.WTT.bUseTimeWindowing) {
    ulError = failCheckCallWindow(pRec,CurrentTime, lpulDialStatus, lpulDelayTime);
    if (ulError) {
      MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failRequestDialPermission, ERROR call to failCheckCallWindow returned ulError %lx\n", ulError);
      return ulError;
    }
    
    MW_SYSLOG_4(TRACE_MWMBL,"unsucces::failRequestDialPermission ulDialStatus %lx ulDelayTime %lx PhoneNumber %s\n", *lpulDialStatus, *lpulDelayTime, pRec->szPhoneNumber);
    return BL_SUCCESSFUL;

  } //end of BL.WTT.bUseTimeWindowing


  // See if the series condition allows dialing.  CheckSeries sets the dial status
  // and delay time.
  ulError = failCheckSeries (pRec, CurrentTime, lpulDialStatus, lpulDelayTime);
  if (ulError) {
    MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failRequestDialPermission, ERROR call to failCheckSeries returned ulError %lx\n", ulError);
    return ulError;
  }

  return BL_SUCCESSFUL;


} //end RequestDialPermission




//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  DialResults
//
//     This function is used to handle the results of a dial from the list
//     in mwblapi.h.  For manual dials, unsuccessful results do not change any
//     phone number status, however, a successful result will clear call
//     restrictions for auto-dialing.
//
//
//
//     Params:   ulDialStatus   - The dial status defined in mwblapi.h as
//                                   SUCCESSFUL
//                                   NO_DIAL_TONE
//                                   LINE_BUSY
//                                   USER_ABORT
//               CurrentTime    - The current time value to work with
//
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from the list in mwblapi.h
//
//-----------------------------------------------------------------------------
ULONG failDialResults ( UnsuccessfulRecord *pRec, ULONG ulDialStatus, time_t CurrentTime)
{
  ULONG ulError;

  MW_SYSLOG_3(TRACE_MWMBL,"unsuccess::failDialResults entry ulDialStatus %lx PhoneNumber %s\n", ulDialStatus, pRec->szPhoneNumber);

  if (!pRec->bInitialized)
    return BLERR_INIT_FAILED + 1200;

  // Check to make sure the number is valid
  if (pRec->szPhoneNumber[0] == '\0')
    return BLERR_PHONE_NUMBER_IS_BLANK;
  

  (void) ulDialStatus;  // clear compiler warnings.  All ulDialStatus values
                        // passed to this function are unsuccessful.  If a
                        // country want's to distinguish different types of
                        // failures then this will be used.

  // If this is a call window algorithm, clean out old time stamps and add the
  // new one.
  if (BL.WTT.bUseTimeWindowing) {
    ulError = failUpdateCallWindow (pRec,CurrentTime);
    if (ulError) {
      MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failDialResults, ERROR, call to failUpdateCallWindow returns ulError %lx\n", ulError);
      return ulError;
    }
    return BL_SUCCESSFUL;
  } 


  // For series blacklisting, we need to update the unsuccessful count.  If the
  // count crosses a boundary then move the status into SERIES_TO_SERIES_DELAY or
  // NUMBER_BLACKLSED.
  ulError = failUpdateSeries (pRec, ulDialStatus, CurrentTime);
  if (ulError) {
    MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failDialResults, ERROR call to failUpdateSeries returns ulError %lx\n", ulError);
    return ulError;
  }
  return BL_SUCCESSFUL;
  
} 



//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  GetNumberInfo
//
//     This function is used to get call restriction information on a number.
//     Memory must be provided by the calling routine.  This function will
//     fill in one NumberListItem structure with call restricted information.
//
//     This routine cleans up timestamps and up dates the unsuccessful count
//     when it is called.  It is possible that the number no longer needed to
//     be tracked after the clean up.  If this is the case,
//     BLERR_PHONE_NUMBER_IS_BLANK will be returned to the caller to tell them
//     that they did not get anything.  The phone number could also be wiped
//     out with a reset or a DialResults call while this routine is running.
//
//
//
//     Params:   lpNumberListItem - A pointer to where call restriction
//                                  information needs to be returned.
//
//               CurrentTime      - The current time value to work with
//
//
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from the list in mwblapi.h
//
//-----------------------------------------------------------------------------
ULONG failGetNumberInfo (UnsuccessfulRecord *pRec, struct BL_NumberListItem FAR *lpNumberListItem,
                                         time_t CurrentTime)
{
  ULONG ulError, ulDialStatus, ulDelayTime;

  if (!pRec->bInitialized)
    return BLERR_INIT_FAILED + 1300;
  
  // Check to make sure the number is valid
  if (pRec->szPhoneNumber[0] == '\0')
    return BLERR_PHONE_NUMBER_IS_BLANK;
  
  if (pRec->ulRecordStatus != NUMBER_BLACKLISTED) {
    // If this is a call window algorithm, clean out old time stamps and find the
    // delay time.
    if (BL.WTT.bUseTimeWindowing) {
      // This is used by the RequestPermission routine to see if dialing can be allowed.
      // We will use it here to determine the delay time.  This call has a side effect in
      // that if all the time stamps are old, then the phone number is deleted from
      // the unsucessful array.
      ulError=failCheckCallWindow (pRec,CurrentTime, &ulDialStatus, &ulDelayTime);
      if (ulError) {
        MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failGetNumberList, ERROR call to failCheckCallWindow returned ulError %lx\n", ulError);
        return ulError;
      }
      
      // Check to make sure the number is still valid
      if (pRec->szPhoneNumber[0] == '\0')
        return BLERR_PHONE_NUMBER_IS_BLANK;

    } else { //series blacklisting
      // This is used by the BL_RequestPermission routine to see if dialing can be allowed.
      // We will use it here to determine the delay time.
      ulError=failCheckSeries(pRec,CurrentTime, &ulDialStatus, &ulDelayTime);
      if (ulError) {
        MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failGetNumberInfo, ERROR call to failCheckSeries returnedulError %lx\n", ulError);
        return ulError;
      }
    }
  } 

  strcpy (lpNumberListItem->szPhoneNumber, pRec->szPhoneNumber);

  lpNumberListItem->bBlacklisted = (pRec->ulRecordStatus == NUMBER_BLACKLISTED);

  lpNumberListItem->ulDelay = ulDelayTime;

  lpNumberListItem->ulUnsuccessfulCount = pRec->ulUnsuccessfulCount;

  lpNumberListItem->ulReserved = 0;

  return BL_SUCCESSFUL;

}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  CleanCallWindow
//
//     This function cleans out the old time stamps from the TimeStampArray
//     and updates the ulUnsuccessfulCount.
//
//
//     Params:   CurrentTime  - the current time to use in removing old time
//                              stamps
//
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from mwblapi.h
//
//--Private--------------------------------------------------------------------
ULONG failCleanCallWindow (UnsuccessfulRecord *pRec, time_t CurrentTime)
{
  USHORT usKeepIndex, usOrigIndex;  // used as an array index, the compiler expects 16 bits
  time_t OldestTimeToKeep;

  // First we need to find out what the threshold is for keeping time stamps.
  // All times are in seconds.
  OldestTimeToKeep = CurrentTime - (time_t) (BL.WTT.ulTimeWindow);

  usKeepIndex = 0;

  for (usOrigIndex = 0; usOrigIndex < MAX_TIME_STAMP_COUNT; usOrigIndex++) {
    if (pRec->TimeStampArray[usOrigIndex] >= OldestTimeToKeep) {
      // move the time stamp up in the list
      pRec->TimeStampArray[usKeepIndex] = pRec->TimeStampArray[usOrigIndex];
      usKeepIndex++;
    }
  }
  // At this point, the usKeepIndex has the unsuccessful count in it
  pRec->ulUnsuccessfulCount = (ULONG) usKeepIndex;

  // Now let's finish by zeroing out the remaining time stamps
  for (usOrigIndex = usKeepIndex; usOrigIndex < MAX_TIME_STAMP_COUNT; usOrigIndex++) {
    pRec->TimeStampArray[usOrigIndex] = 0;
  }

  return BL_SUCCESSFUL;
}


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  CheckCallWindow
//
//     This function calls CleanCallWindow to clean out the old time stamps,
//     updates ulUnsuccessfulCount for the record, and determines if it is
//     OK to dial.
//
//
//     Params:   CurrentTime    - the current time to use in removing old time stamps
//               lpulDialStatus - A pointer to return the status of the request:
//                                BL_DIAL_GRANTED       - OK to dial
//                                BL_NUMBER_DELAYED     - permission denied for
//                                                        lpulDelayTime more seconds
//               lpulDelayTime  - a pointer to return the delay time in seconds
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from mwblapi.h
//
//---Private-------------------------------------------------------------------
ULONG failCheckCallWindow (UnsuccessfulRecord *pRec, time_t CurrentTime, ULONG FAR *lpulDialStatus,
                                           ULONG FAR *lpulDelayTime)
{
  ULONG ulError;
  time_t ElapsedTime;


  // Remove the old time stamps that are outside the time window.  CleanCallWindow
  // also updates the ulUnsuccessfulCount.
  ulError = failCleanCallWindow (pRec,CurrentTime);
  if (ulError) {
    MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failCheckCallWindow, ERROR call to failCleanCallWindow returnes ulError %lx\n", ulError);
    return ulError;
  }
  
  // If the remaining unsuccessful count is zero, grant the call.
  if (pRec->ulUnsuccessfulCount == 0)  {
    *lpulDialStatus = BL_DIAL_GRANTED;
    *lpulDelayTime = 0;
    
    return BL_SUCCESSFUL;
  }
  
  
  if (pRec->ulUnsuccessfulCount >= BL.WTT.ulMaxUnsuccessfulCount) {
    *lpulDialStatus = BL_NUMBER_DELAYED;
    
    // Since the oldest time stamp is always in the zero index element of the
    // time stamp array, use this time to determine the delay.
    *lpulDelayTime = BL.WTT.ulTimeWindow - (CurrentTime - pRec->TimeStampArray[0]);
  } else {
    // The count is not too large, check the retry times.
    ElapsedTime = CurrentTime - failFindLatestTimeStamp(pRec);

    if (BL.WTT.ulUnsuccessfulRetryDelay > (ULONG)ElapsedTime) {
      // Fail the request
      *lpulDialStatus = BL_NUMBER_DELAYED;
      *lpulDelayTime = BL.WTT.ulUnsuccessfulRetryDelay - ElapsedTime;
    } else {
      *lpulDialStatus = BL_DIAL_GRANTED;
      *lpulDelayTime = 0;
    }
  }
  
  return BL_SUCCESSFUL;
} 


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  CheckSeries
//
//     This function determines if it is OK to dial based on the series type
//     blacklisting.
//
//     Params:   CurrentTime    - the current time to use in removing old time stamps
//               lpulDialStatus - A pointer to return the status of the request:
//                                BL_DIAL_GRANTED       - OK to dial
//                                BL_NUMBER_DELAYED     - permission denied for
//                                                        lpulDelayTime more seconds
//               lpulDelayTime  - a pointer to return the delay time in seconds
//
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from mwblapi.h
//
//---Private-------------------------------------------------------------------
ULONG failCheckSeries (UnsuccessfulRecord *pRec, time_t CurrentTime, ULONG FAR *lpulDialStatus,
                                       ULONG FAR *lpulDelayTime)
{
  time_t ElapsedTime;

  *lpulDelayTime = 0;


  //Assume that the BL_DialResults is handling the situation when the count
  //hits the maximum allowed.  Also, if the number is blacklisted it is
  //handled and this routine is not called.  In this case, we are only enforcing
  //retry delays.  For series type blacklisting, only the [0] element of the
  //TimeStampArray is used to record the last unsuccessful attempt.
  ElapsedTime = CurrentTime - pRec->TimeStampArray[0];


  // This implementation does not distinguish between the first and second series
  if ((pRec->ulRecordStatus == FIRST_SERIES) || (pRec->ulRecordStatus == SECOND_SERIES)) {
    if (pRec->ulUnsuccessfulCount == 1) { // this is the first retry
      if (BL.WTT.ulFirstRetryDelay > (ULONG)ElapsedTime) {
        *lpulDialStatus = BL_NUMBER_DELAYED;
        *lpulDelayTime = BL.WTT.ulFirstRetryDelay - ElapsedTime;
      } else
        *lpulDialStatus = BL_DIAL_GRANTED;
    } else {
      if (BL.WTT.ulUnsuccessfulRetryDelay > (ULONG)ElapsedTime) {
        *lpulDialStatus = BL_NUMBER_DELAYED;
        *lpulDelayTime = BL.WTT.ulUnsuccessfulRetryDelay - ElapsedTime;
      } else
        *lpulDialStatus = BL_DIAL_GRANTED;
    }
  } else if (pRec->ulRecordStatus == SERIES_TO_SERIES_DELAY) {
    MW_SYSLOG_3(TRACE_MWMBL,"unsucces::failCheckSeries, SeriesToSeriesDelay %lx ElapsedTime %lx\n", BL.WTT.ulSeriesToSeriesDelay, ElapsedTime);
    
    if (BL.WTT.ulSeriesToSeriesDelay > (ULONG)ElapsedTime) {
      *lpulDialStatus = BL_NUMBER_DELAYED;
      *lpulDelayTime = BL.WTT.ulSeriesToSeriesDelay - ElapsedTime;
    } else {
      // The series to series delay time has expired, move the status to second
      // series and allow the call.
      pRec->ulRecordStatus = SECOND_SERIES;
      *lpulDialStatus = BL_DIAL_GRANTED;
    }
  } else {
    MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failCheckSeries, ERROR ulRecordStatus %lx is corrupt\n", pRec->ulRecordStatus);
    return BLERR_INTERNAL_ERROR;
  }

  MW_SYSLOG_4(TRACE_MWMBL,"unuscces::failCheckSeries exit with ulRecordStatus %lx ulDialStatus %lx ulDelayTime %lx\n", pRec->ulRecordStatus, *lpulDialStatus, *lpulDelayTime);
  return BL_SUCCESSFUL;

}


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  UpdateCallWindow
//
//     This function is called when an unsuccessful call occurs.  The times
//     stamp array is cleaned up and the new time stamp is added.
//
//     Params:   CurrentTime    - the current time to use in setting a new time stamps
//                                and removing old ones.
//
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from mwblapi.h
//
//---Private-------------------------------------------------------------------
ULONG failUpdateCallWindow (UnsuccessfulRecord *pRec, time_t CurrentTime)
{
  ULONG ulError;
  USHORT usIndex; // used as an array index, the compiler expects 16 bits
  
  // Remove the old time stamps that are outside the time window.  CleanCallWindow
  // also updates the ulUnsuccessfulCount.
  ulError = failCleanCallWindow (pRec,CurrentTime);
  if (ulError) {
    MW_SYSLOG_2(TRACE_MWMBL,"unsucces::failUpdateCallWindow, ERROR call to failCleanCallWindow returned ulError %lx\n", ulError);
    return ulError;
  }
  
  // Now place the new time stamp at the end of the list.  Because the maximum unsuccessful
  // count was checked against the size of the time stamp array when the WT Table
  // loaded, there should always be an available time stamp location.

  for (usIndex = 0; usIndex < MAX_TIME_STAMP_COUNT; usIndex++) {
    if (pRec->TimeStampArray[usIndex] == 0) {
      pRec->TimeStampArray[usIndex] = CurrentTime;
      break;  // drop out the for loop
    }
  }
  
  // bump up the count
  pRec->ulUnsuccessfulCount++;
  return BL_SUCCESSFUL;

} 


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
//  UpdateSeries
//
//     This function is called when an unsuccessful call occurs.  The unsuccessful
//     count is updated.  If this causes a series transition, then this is handled
//     here also.
//
//     Params:   ulDialStatus   - The dial status defined in mwblapi.h as
//                                   SUCCESSFUL
//                                   NO_DIAL_TONE
//                                   LINE_BUSY
//                                   USER_ABORT
//               CurrentTime    - the current time to use in setting a new time stamps
//                                and removing old ones.
//
//
//     Returns:  ULONG Successful:  0
//                     Error:       BLERR_.... from mwblapi.h
//
//---Private-------------------------------------------------------------------
ULONG failUpdateSeries (UnsuccessfulRecord *pRec, ULONG ulDialStatus, time_t CurrentTime)
{
  BOOL bBoundaryCrossed = FALSE;

  // Update the last dial time stamp
  pRec->TimeStampArray[0] = CurrentTime;

  // First let's bump up the unsuccessful count
  pRec->ulUnsuccessfulCount++;

  // Next we need to see if the count crossed a boundary
  if (pRec->ulUnsuccessfulCount >= BL.WTT.ulMaxUnsuccessfulCount)
    bBoundaryCrossed = TRUE;


  //..Special code for Canada................................................
  // Canada's CS-03 Part 1 specification Issue 8 on page I-123, section 3.9.1
  // requires:  "Automatic dialing to any individual number is limited to 2
  // successive attempts.  Automatic dialing equipment which employ means for
  // detecting both busy and reorder signals shall be permitted an additional
  // 13 attempts if a busy or reorder signal is encountered on each attempt."
  //
  // This implementation makes sure that if only LINE_BUSY status is reported,
  // then up to 15 unsuccessful attempts can be made.

  if (BL.WTT.bUseSpecialAlgorithm &&
      (BL.WTT.ulCountryNumber == WT_COUNTRY_CANADA)) {
    // If the unsuccessful condition is always LINE_BUSY, then up to 15 tries is
    // allowed in Canada.
    if (ulDialStatus != LINE_BUSY)
      pRec->ulNonBusyUnsuccessfulCount++;

    else if ( !pRec->ulNonBusyUnsuccessfulCount && (pRec->ulUnsuccessfulCount < 15))  // LINE_BUSY is the status
      bBoundaryCrossed = FALSE;
  }
  //..End Canada special code ...............................................
  
  

  if (bBoundaryCrossed) {
    if (pRec->ulRecordStatus == FIRST_SERIES) {
      if (BL.WTT.bBlacklistAfterFirstSeries) {
        pRec->ulRecordStatus = NUMBER_BLACKLISTED;
      } else {
        pRec->ulRecordStatus = SERIES_TO_SERIES_DELAY;
      }
    } else if (pRec->ulRecordStatus == SECOND_SERIES) {
      if (BL.WTT.bBlacklistAfterSecondSeries) {
        pRec->ulRecordStatus = NUMBER_BLACKLISTED;
      } else {
        pRec->ulRecordStatus = SERIES_TO_SERIES_DELAY;
      }
    } else {
      MW_SYSLOG_1(TRACE_MWMBL,"unsucces::failUpdateSeries, ERROR failed with a corrupt ulRecordStatus\n");
      return BLERR_INTERNAL_ERROR;
    }
    
    // Set the count back to zero
    pRec->ulUnsuccessfulCount = 0;

    // Set the non-busy unsuccessful count used in Canada back to zero
    pRec->ulNonBusyUnsuccessfulCount = 0;

  } // end if we crossed a count boundary


  MW_SYSLOG_4(TRACE_MWMBL,"unsucces::failUpdateSeries exit ulRecordStatus %lx ulUnsuccessfulCount %lx ulNonBusyUnsuccessfulCount %lx\n", pRec->ulRecordStatus, pRec->ulUnsuccessfulCount, pRec->ulNonBusyUnsuccessfulCount);

  return BL_SUCCESSFUL;

} 

ULONG failIsNumberBlacklisted(UnsuccessfulRecord *pRec) {

  return (pRec->ulRecordStatus == NUMBER_BLACKLISTED);
}