]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/i4b/isdnd/support.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / usr.sbin / i4b / isdnd / support.c
1 /*
2  * Copyright (c) 1997, 2003 Hellmuth Michaelis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b daemon - misc support routines
28  *      ----------------------------------
29  *
30  * $FreeBSD$
31  *
32  *      last edit-date: [Sat May 13 13:19:23 2006]
33  *
34  *---------------------------------------------------------------------------*/
35
36 #include "isdnd.h"
37
38 static int isvalidtime(cfg_entry_t *cep);
39         
40 /*---------------------------------------------------------------------------*
41  *      find an active entry by driver type and driver unit
42  *---------------------------------------------------------------------------*/
43 cfg_entry_t *
44 find_active_entry_by_driver(int drivertype, int driverunit)
45 {
46         cfg_entry_t *cep = NULL;
47         int i;
48
49         for(i=0; i < nentries; i++)
50         {
51                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
52
53                 if(!((cep->usrdevicename == drivertype) &&
54                      (cep->usrdeviceunit == driverunit)))
55                 {
56                         continue;
57                 }
58
59                 /* check time interval */
60                 
61                 if(isvalidtime(cep) == 0)
62                 {
63                         DBGL(DL_VALID, (llog(LL_DBG, "find_active_entry_by_driver: entry %d, time not valid!", i)));
64                         continue;
65                 }
66                 
67                 /* found */
68                 
69                 if(cep->cdid == CDID_UNUSED)
70                 {
71                         DBGL(DL_MSG, (llog(LL_DBG, "find_active_entry_by_driver: entry %d [%s%d], cdid=CDID_UNUSED !",
72                                 i, bdrivername(drivertype), driverunit)));
73                         return(NULL);
74                 }
75                 else if(cep->cdid == CDID_RESERVED)
76                 {
77                         DBGL(DL_MSG, (llog(LL_DBG, "find_active_entry_by_driver: entry %d [%s%d], cdid=CDID_RESERVED!",
78                                 i, bdrivername(drivertype), driverunit)));
79                         return(NULL);
80                 }
81                 return(cep);
82         }
83         return(NULL);
84 }
85
86 /*---------------------------------------------------------------------------*
87  *      find entry by drivertype and driverunit and setup for dialing out
88  *---------------------------------------------------------------------------*/
89 cfg_entry_t *
90 find_by_device_for_dialout(int drivertype, int driverunit)
91 {
92         cfg_entry_t *cep = NULL;
93         int i;
94
95         for(i=0; i < nentries; i++)
96         {
97                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
98
99                 /* compare driver type and unit */
100
101                 if(!((cep->usrdevicename == drivertype) &&
102                      (cep->usrdeviceunit == driverunit)))
103                 {
104                         continue;
105                 }
106
107                 /* check time interval */
108                 
109                 if(isvalidtime(cep) == 0)
110                 {
111                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialout: entry %d, time not valid!", i)));
112                         continue;
113                 }
114                 
115                 /* found, check if already reserved */
116                 
117                 if(cep->cdid == CDID_RESERVED)
118                 {
119                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialout: entry %d, cdid reserved!", i)));
120                         return(NULL);
121                 }
122
123                 /* check if this entry is already in use ? */
124                 
125                 if(cep->cdid != CDID_UNUSED)    
126                 {
127                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialout: entry %d, cdid in use", i)));
128                         return(NULL);
129                 }
130
131                 if((setup_dialout(cep)) == GOOD)
132                 {
133                         /* found an entry to be used for calling out */
134                 
135                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialout: found entry %d!", i)));
136                         return(cep);
137                 }
138                 else
139                 {
140                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialout: entry %d, setup_dialout() failed!", i)));
141                         return(NULL);
142                 }
143         }
144
145         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialout: no entry found!")));
146         return(NULL);
147 }
148
149 /*---------------------------------------------------------------------------*
150  *      find entry by drivertype and driverunit and setup for dialing out
151  *---------------------------------------------------------------------------*/
152 cfg_entry_t *
153 find_by_device_for_dialoutnumber(msg_dialoutnumber_ind_t *mp)
154 {
155         cfg_entry_t *cep = NULL;
156         int i, j;
157
158         for(i=0; i < nentries; i++)
159         {
160                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
161
162                 /* compare driver type and unit */
163
164                 if(!((cep->usrdevicename == mp->driver) &&
165                      (cep->usrdeviceunit == mp->driver_unit)))
166                 {
167                         continue;
168                 }
169
170                 /* check time interval */
171                 
172                 if(isvalidtime(cep) == 0)
173                 {
174                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, time not valid!", i)));
175                         continue;
176                 }
177
178                 /* found, check if already reserved */
179                 
180                 if(cep->cdid == CDID_RESERVED)
181                 {
182                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid reserved!", i)));
183                         return(NULL);
184                 }
185
186                 /* check if this entry is already in use ? */
187                 
188                 if(cep->cdid != CDID_UNUSED)    
189                 {
190                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid in use", i)));
191                         return(NULL);
192                 }
193
194                 cep->keypad[0] = '\0';
195                 
196                 /* check number and copy to cep->remote_numbers[] */
197                 
198                 for(j = 0; j < mp->cmdlen; j++)
199                 {
200                         if(!(isdigit(*(mp->cmd+j))))
201                         {
202                                 DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, dial string contains non-digit at pos %d", i, j)));
203                                 return(NULL);
204                         }
205                         /* fill in number to dial */
206                         cep->remote_numbers[0].number[j] = *(mp->cmd+j);
207                 }                               
208                 cep->remote_numbers[0].number[j] = '\0';
209
210 /* XXX subaddr does not have to be a digit! isgraph() would be a better idea */
211                 for(j = 0; j < mp->subaddrlen; j++)
212                 {
213                         if(!(isdigit(*(mp->subaddr+j))))
214                         {
215                                 DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, subaddr string contains non-digit at pos %d", i, j)));
216                                 return(NULL);
217                         }
218                         /* fill in number to dial */
219                         cep->remote_numbers[0].subaddr[j] = *(mp->subaddr+j);
220                 }                               
221                 cep->remote_numbers[0].subaddr[j] = '\0';
222
223                 cep->remote_numbers_count = 1;
224
225                 if((setup_dialout(cep)) == GOOD)
226                 {
227                         /* found an entry to be used for calling out */
228                 
229                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialoutnumber: found entry %d!", i)));
230                         return(cep);
231                 }
232                 else
233                 {
234                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, setup_dialout() failed!", i)));
235                         return(NULL);
236                 }
237         }
238
239         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_dialoutnumber: no entry found!")));
240         return(NULL);
241 }
242
243 /*---------------------------------------------------------------------------*
244  *      find entry by drivertype and driverunit and setup for send keypad
245  *---------------------------------------------------------------------------*/
246 cfg_entry_t *
247 find_by_device_for_keypad(int drivertype, int driverunit, int cmdlen, char *cmd)
248 {
249         cfg_entry_t *cep = NULL;
250         int i;
251
252         for(i=0; i < nentries; i++)
253         {
254                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
255
256                 /* compare driver type and unit */
257
258                 if(!((cep->usrdevicename == drivertype) &&
259                      (cep->usrdeviceunit == driverunit)))
260                 {
261                         continue;
262                 }
263
264                 /* check time interval */
265                 
266                 if(isvalidtime(cep) == 0)
267                 {
268                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_keypad: entry %d, time not valid!", i)));
269                         continue;
270                 }
271
272                 /* found, check if already reserved */
273                 
274                 if(cep->cdid == CDID_RESERVED)
275                 {
276                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_keypad: entry %d, cdid reserved!", i)));
277                         return(NULL);
278                 }
279
280                 /* check if this entry is already in use ? */
281                 
282                 if(cep->cdid != CDID_UNUSED)    
283                 {
284                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_keypad: entry %d, cdid in use", i)));
285                         return(NULL);
286                 }
287
288                 cep->remote_numbers[0].number[0] = '\0';
289                 cep->remote_numbers_count = 0;
290                 cep->remote_phone_dialout.number[0] = '\0';
291                 
292                 bzero(cep->keypad, KEYPAD_MAX);
293                 strncpy(cep->keypad, cmd, cmdlen);
294
295                 DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_keypad: entry %d, keypad string is %s", i, cep->keypad)));
296
297                 if((setup_dialout(cep)) == GOOD)
298                 {
299                         /* found an entry to be used for calling out */
300                 
301                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_keypad: found entry %d!", i)));
302                         return(cep);
303                 }
304                 else
305                 {
306                         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_keypad: entry %d, setup_dialout() failed!", i)));
307                         return(NULL);
308                 }
309         }
310
311         DBGL(DL_MSG, (llog(LL_DBG, "find_by_device_for_keypad: no entry found!")));
312         return(NULL);
313 }
314
315 /*---------------------------------------------------------------------------*
316  *      find entry by drivertype and driverunit and setup for dialing out
317  *---------------------------------------------------------------------------*/
318 int
319 setup_dialout(cfg_entry_t *cep)
320 {
321         int i;
322     
323         /* check controller operational */
324
325         if((get_controller_state(cep->isdncontroller)) != CTRL_UP)
326         {
327                 DBGL(DL_MSG, (llog(LL_DBG, "setup_dialout: entry %s, controller is down", cep->name)));
328                 return(ERROR);
329         }
330
331         cep->isdncontrollerused = cep->isdncontroller;
332
333         /* check channel available */
334
335         switch(cep->isdnchannel)
336         {
337                 case CHAN_ANY:
338                     for (i = 0; i < isdn_ctrl_tab[cep->isdncontroller].nbch; i++)
339                         {
340                         if(ret_channel_state(cep->isdncontroller, i) == CHAN_IDLE)
341                         break;
342                     }
343
344                     if (i == isdn_ctrl_tab[cep->isdncontroller].nbch)
345                         {
346                                 DBGL(DL_MSG, (llog(LL_DBG, "setup_dialout: entry %s, no channel free", cep->name)));
347                                 return(ERROR);
348                         }
349                         cep->isdnchannelused = CHAN_ANY;
350                         break;
351
352                 default:
353                         if((ret_channel_state(cep->isdncontroller, cep->isdnchannel)) != CHAN_IDLE)
354                         {
355                                 DBGL(DL_MSG, (llog(LL_DBG, "setup_dialout: entry %s, channel not free", cep->name)));
356                         return(ERROR);
357                         }
358                         cep->isdnchannelused = cep->isdnchannel;
359                         break;
360         }
361
362         DBGL(DL_MSG, (llog(LL_DBG, "setup_dialout: entry %s ok!", cep->name)));
363
364         /* preset disconnect cause */
365         
366         SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B);
367         SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_NORMAL);
368         
369         return(GOOD);
370 }
371
372 /*---------------------------------------------------------------------------*
373  *      find entry by drivertype and driverunit
374  *---------------------------------------------------------------------------*/
375 cfg_entry_t *
376 get_cep_by_driver(int drivertype, int driverunit)
377 {
378         cfg_entry_t *cep = NULL;
379         int i;
380
381         for(i=0; i < nentries; i++)
382         {
383                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
384
385                 if(!((cep->usrdevicename == drivertype) &&
386                      (cep->usrdeviceunit == driverunit)))
387                 {
388                         continue;
389                 }
390
391                 /* check time interval */
392                 
393                 if(isvalidtime(cep) == 0)
394                 {
395                         DBGL(DL_MSG, (llog(LL_DBG, "get_cep_by_driver: entry %d, time not valid!", i)));
396                         continue;
397                 }               
398
399                 DBGL(DL_MSG, (llog(LL_DBG, "get_cep_by_driver: found entry %d!", i)));
400                 return(cep);
401         }
402         return(NULL);
403 }
404
405 /*---------------------------------------------------------------------------*
406  *      find a matching entry for an incoming call
407  *
408  *      - not found/no match: log output with LL_CHD and return NULL
409  *      - found/match: make entry in free cep, return address
410  *---------------------------------------------------------------------------*/
411 cfg_entry_t *
412 find_matching_entry_incoming(msg_connect_ind_t *mp)
413 {
414         cfg_entry_t *cep = NULL;
415         int i;
416
417         /* check for CW (call waiting) early */
418
419         if(mp->channel == CHAN_NO)
420         {
421                 if(aliasing)
422                 {
423                         char *src_tela = "ERROR-src_tela";
424                         char *dst_tela = "ERROR-dst_tela";
425         
426                         src_tela = get_alias(mp->src_telno);
427                         dst_tela = get_alias(mp->dst_telno);
428         
429                         llog(LL_CHD, "%05d <unknown> CW from %s to %s (no channel free)",
430                                 mp->header.cdid, src_tela, dst_tela);
431                 }
432                 else
433                 {
434                         llog(LL_CHD, "%05d <unknown> call waiting from %s to %s (no channel free)",
435                                 mp->header.cdid, mp->src_telno, mp->dst_telno);
436                 }
437                 return(NULL);
438         }
439         
440         for(i=0; i < nentries; i++)
441         {
442                 int n;
443                 cep = &cfg_entry_tab[i];        /* ptr to config entry */
444
445                 /* check my number */
446
447                 if(strncmp(cep->local_phone_incoming.number, mp->dst_telno, strlen(cep->local_phone_incoming.number)))
448                 {
449                         DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, myno %s != incomingno %s", i,
450                                 cep->local_phone_incoming.number, mp->dst_telno)));
451                         continue;
452                 }
453
454                 if (cep->usesubaddr && strncmp(cep->local_phone_incoming.subaddr, mp->dst_subaddr, strlen(cep->local_phone_incoming.subaddr)))
455                 {
456                         DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, mysubno %s != incomingsubno %s", i,
457                                 cep->local_phone_incoming.subaddr, mp->dst_subaddr)));
458                         continue;
459                 }
460
461                 /* check all allowed remote numbers for this entry */
462
463                 for (n = 0; n < cep->incoming_numbers_count; n++)
464                 {
465                         incoming_number_t *in = &cep->remote_phone_incoming[n];
466
467                         /*
468                          * An incoming number matches whenever the main 
469                          * phone number either matches or is a wildcard AND
470                          * subaddresses are either not in use or match as 
471                          * well (or the required subaddress is a wildcard). 
472                          * This means that if subaddresses are in use and
473                          * the main phone number is a wildcard, the 
474                          * subaddress is still required to match. 
475                          *
476                          * At first glance, this does not seem logical,
477                          * but since subaddress usage can be configured per
478                          * entry, disregarding the subaddress if the main 
479                          * number matches would needlessly limit the user's
480                          * flexibility.
481                          */
482
483                         if ((in->number[0] == '*') || (!strncmp(in->number, mp->src_telno, strlen(in->number))))
484                         {
485                                 if ((!cep->usesubaddr) || (in->subaddr[0] == '*') || (!strncmp(in->subaddr, mp->src_subaddr, strlen(in->subaddr))))
486                                 {
487                                         DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, match: remno %s = incomingfromno %s", i,
488                                                 in->number, mp->src_telno)));
489                                         break;
490                                 }
491                         }
492                         else
493                         {
494                                 DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, remno %s != incomingfromno %s", i,
495                                         in->number, mp->src_telno)));
496                         }
497                 }
498
499                 /* If all configured remote numbers have been tested without success, proceed to the next entry. */
500                 if (n >= cep->incoming_numbers_count)
501                         continue;
502
503                 /* check b protocol */
504
505                 if(cep->b1protocol != mp->bprot)
506                 {
507                         DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, bprot %d != incomingprot %d", i,
508                                 cep->b1protocol, mp->bprot)));
509                         continue;
510                 }
511
512                 /* is this entry currently in use ? */
513
514                 if(cep->cdid != CDID_UNUSED)
515                 {
516                         if(cep->cdid == CDID_RESERVED)
517                         {
518                                 DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, cdid is reserved", i)));
519                         }
520                         else if (cep->dialin_reaction == REACT_ACCEPT
521                                  && cep->dialouttype == DIALOUT_CALLEDBACK)
522                         {
523                                 /*
524                                  * We might consider doing this even if this is
525                                  * not a calledback config entry - BUT: there are
526                                  * severe race conditions and timinig problems
527                                  * ex. if both sides run I4B with no callback
528                                  * delay - both may shutdown the outgoing call
529                                  * and never be able to establish a connection.
530                                  * In the called-back case this should not happen.
531                                  */
532                                 DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, incoming call for callback in progress (cdid %05d)", i, cep->cdid)));
533
534                                 /* save the current call state, we're going to overwrite it with the
535                                  * new incoming state below... */
536                                 cep->saved_call.cdid = cep->cdid;
537                                 cep->saved_call.controller = cep->isdncontrollerused;
538                                 cep->saved_call.channel = cep->isdnchannelused;
539                         }
540                         else
541                         {
542                                 DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, cdid in use", i)));
543                                 continue;       /* yes, next */
544                         }
545                 }
546
547                 /* check controller value ok */
548
549                 if(mp->controller > ncontroller)
550                 {
551                         llog(LL_CHD, "%05d %s incoming call with invalid controller %d",
552                                 mp->header.cdid, cep->name, mp->controller);
553                         return(NULL);
554                 }
555
556                 /* check controller marked up */
557
558                 if((get_controller_state(mp->controller)) != CTRL_UP)
559                 {
560                         llog(LL_CHD, "%05d %s incoming call, controller %d DOWN!",
561                                 mp->header.cdid, cep->name, mp->controller);
562                         return(NULL);
563                 }
564
565                 /* 
566                  * check controller he wants, check for any 
567                  * controller or specific controller 
568                  */
569
570                 if( (mp->controller != -1) && 
571                     (mp->controller != cep->isdncontroller) )
572                 {
573                         llog(LL_CHD, "%05d %s incoming call, controller %d != incoming %d",
574                                 mp->header.cdid, cep->name, 
575                                 cep->isdncontroller, mp->controller);
576                         continue;
577                 }
578
579                 /* check channel he wants */
580
581                 switch(mp->channel)
582                 {
583                         case CHAN_ANY:
584                             for (i = 0; i < isdn_ctrl_tab[mp->controller].nbch; i++)
585                                 {
586                                 if(ret_channel_state(mp->controller, i) == CHAN_IDLE)
587                                 break;
588                             }
589
590                             if (i == isdn_ctrl_tab[mp->controller].nbch)
591                                 {
592                                         llog(LL_CHD, "%05d %s incoming call, no channel free!",
593                                                 mp->header.cdid, cep->name);
594                                         return(NULL);
595                                 }
596                                 break;
597
598                         case CHAN_NO:
599                                 llog(LL_CHD, "%05d %s incoming call, call waiting (no channel available)!",
600                                         mp->header.cdid, cep->name);
601                                 return(NULL);
602                                 break;
603
604                         default:
605                                 if((ret_channel_state(mp->controller, mp->channel)) != CHAN_IDLE)
606                                 {
607                                         llog(LL_CHD, "%05d %s incoming call, channel B%d not free!",
608                                                 mp->header.cdid, cep->name, mp->channel+1);
609                                 return(NULL);
610                                 }
611                                 break;
612                 }
613
614                 /* check time interval */
615                 
616                 if(isvalidtime(cep) == 0)
617                 {
618                         DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, time not valid!", i)));
619                         continue;
620                 }
621                 
622                 /* found a matching entry */
623
624                 cep->cdid = mp->header.cdid;
625                 cep->isdncontrollerused = mp->controller;
626                 cep->isdnchannelused = mp->channel;
627 /*XXX*/         cep->disc_cause = 0;
628                 
629                 /* cp number to real one used */
630                 
631                 strcpy(cep->real_phone_incoming.number, mp->src_telno);
632
633                 /* copy display string */
634                 
635                 strcpy(cep->display, mp->display);
636                 
637                 /* entry currently down ? */
638                 
639                 if(cep->state == ST_DOWN)
640                 {
641                         msg_updown_ind_t mui;
642                         
643                         /* set interface up */
644         
645                         DBGL(DL_MSG, (llog(LL_DBG, "find_matching_entry_incoming: entry %d, ", i)));
646         
647                         mui.driver = cep->usrdevicename;
648                         mui.driver_unit = cep->usrdeviceunit;
649                         mui.updown = SOFT_ENA;
650                         
651                         if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
652                         {
653                                 llog(LL_ERR, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
654                                 error_exit(1, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
655                         }
656
657                         cep->down_retry_count = 0;
658                         cep->state = ST_IDLE;
659                 }
660                 return(cep);
661         }
662
663         if(aliasing)
664         {
665                 char *src_tela = "ERROR-src_tela";
666                 char *dst_tela = "ERROR-dst_tela";
667
668                 src_tela = get_alias(mp->src_telno);
669                 dst_tela = get_alias(mp->dst_telno);
670
671                 llog(LL_CHD, "%05d Call from %s to %s",
672                         mp->header.cdid, src_tela, dst_tela);
673         }
674         else
675         {
676                 llog(LL_CHD, "%05d <unknown> incoming call from %s to %s ctrl %d",
677                         mp->header.cdid, mp->src_telno, mp->dst_telno, mp->controller);
678         }
679         return(NULL);
680 }
681
682 /*---------------------------------------------------------------------------*
683  *      return address of ACTIVE config entry by controller and channel
684  *---------------------------------------------------------------------------*/
685 cfg_entry_t *
686 get_cep_by_cc(int ctrlr, int chan)
687 {
688         int i;
689
690         if((chan < 0) || (chan >= isdn_ctrl_tab[ctrlr].nbch))
691                 return(NULL);
692                 
693         for(i=0; i < nentries; i++)
694         {
695                 if((cfg_entry_tab[i].cdid != CDID_UNUSED)               &&
696                    (cfg_entry_tab[i].cdid != CDID_RESERVED)             &&
697                    (cfg_entry_tab[i].isdnchannelused == chan)           &&
698                    (cfg_entry_tab[i].isdncontrollerused == ctrlr)       &&
699                    ((ret_channel_state(ctrlr, chan)) == CHAN_RUN))
700                 {
701                         return(&cfg_entry_tab[i]);
702                 }
703         }
704         return(NULL);
705 }
706
707 /*---------------------------------------------------------------------------*
708  *      return address of config entry identified by cdid
709  *---------------------------------------------------------------------------*/
710 cfg_entry_t *
711 get_cep_by_cdid(int cdid)
712 {
713         int i;
714
715         for(i=0; i < nentries; i++)
716         {
717                 if(cfg_entry_tab[i].cdid == cdid
718                   || cfg_entry_tab[i].saved_call.cdid == cdid)
719                         return(&cfg_entry_tab[i]);
720         }
721         return(NULL);
722 }
723
724 /*---------------------------------------------------------------------------*
725  *      return b channel driver type name string
726  *---------------------------------------------------------------------------*/
727 char *
728 bdrivername(int drivertype)
729 {
730         static char *bdtab[] = {
731                 "rbch",
732                 "tel",
733                 "ipr",
734                 "isp",
735                 "ibc",
736                 "ing"
737         };
738
739         if(drivertype >= BDRV_RBCH && drivertype <= BDRV_ING)
740                 return(bdtab[drivertype]);
741         else
742                 return("unknown");
743 }
744
745 /*---------------------------------------------------------------------------*
746  *      process AOCD charging messages
747  *---------------------------------------------------------------------------*/
748 void
749 handle_charge(cfg_entry_t *cep)
750 {
751         time_t now = time(NULL);
752
753         if(cep->aoc_last == 0)          /* no last timestamp yet ? */
754         {
755                 cep->aoc_last = now;    /* add time stamp */
756         }
757         else if(cep->aoc_now == 0)      /* no current timestamp yet ? */
758         {
759                 cep->aoc_now = now;     /* current timestamp */
760         }
761         else
762         {
763                 cep->aoc_last = cep->aoc_now;
764                 cep->aoc_now = now;
765                 cep->aoc_diff = cep->aoc_now - cep->aoc_last;
766                 cep->aoc_valid = AOC_VALID;
767         }
768         
769 #ifdef USE_CURSES
770         if(do_fullscreen)
771                 display_charge(cep);
772 #endif
773
774 #ifdef I4B_EXTERNAL_MONITOR
775         if(do_monitor && accepted)
776                 monitor_evnt_charge(cep, cep->charge, 0);
777 #endif
778
779         if(cep->aoc_valid == AOC_VALID)
780         {
781                 if(cep->aoc_diff != cep->unitlength)
782                 {
783                         DBGL(DL_MSG, (llog(LL_DBG, "handle_charge: AOCD unit length updated %d -> %d secs", cep->unitlength, cep->aoc_diff)));
784
785                         cep->unitlength = cep->aoc_diff;
786
787                         unitlen_chkupd(cep);
788                 }
789                 else
790                 {
791 #ifdef NOTDEF
792                         DBGL(DL_MSG, (llog(LL_DBG, "handle_charge: AOCD unit length still %d secs", cep->unitlength)));
793 #endif
794                 }
795         }
796 }
797
798 /*---------------------------------------------------------------------------*
799  *      update kernel idle_time, earlyhup_time and unitlen_time
800  *---------------------------------------------------------------------------*/
801 void
802 unitlen_chkupd(cfg_entry_t *cep)
803 {
804         msg_timeout_upd_t tupd;
805
806         tupd.cdid = cep->cdid;
807
808         /* init the short hold data based on the shorthold algorithm type */
809         
810         switch(cep->shorthold_algorithm)
811         {
812                 case SHA_FIXU:
813                         tupd.shorthold_data.shorthold_algorithm = SHA_FIXU;
814                         tupd.shorthold_data.unitlen_time = cep->unitlength;
815                         tupd.shorthold_data.idle_time = cep->idle_time_out;
816                         tupd.shorthold_data.earlyhup_time = cep->earlyhangup;
817                         break;
818
819                 case SHA_VARU:
820                         tupd.shorthold_data.shorthold_algorithm = SHA_VARU;
821                         tupd.shorthold_data.unitlen_time = cep->unitlength;
822                         tupd.shorthold_data.idle_time = cep->idle_time_out;
823                         tupd.shorthold_data.earlyhup_time = 0;
824                         break;
825                 default:
826                         llog(LL_ERR, "unitlen_chkupd bad shorthold_algorithm %d", cep->shorthold_algorithm );
827                         return;
828                         break;                  
829         }
830
831         if((ioctl(isdnfd, I4B_TIMEOUT_UPD, &tupd)) < 0)
832         {
833                 llog(LL_ERR, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno));
834                 error_exit(1, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno));
835         }
836 }
837
838 /*--------------------------------------------------------------------------*
839  *      this is intended to be called by do_exit and closes down all
840  *      active connections before the daemon exits or is reconfigured.
841  *--------------------------------------------------------------------------*/
842 void
843 close_allactive(void)
844 {
845         int i, j, k;
846         cfg_entry_t *cep = NULL;
847
848         j = 0;
849         
850         for (i = 0; i < ncontroller; i++)
851         {
852                 if((get_controller_state(i)) != CTRL_UP)
853                         continue;
854
855                 for (k = 0; k < isdn_ctrl_tab[i].nbch; k++)
856                 {
857                     if((ret_channel_state(i, k)) == CHAN_RUN)
858                         {
859                         if((cep = get_cep_by_cc(i, k)) != NULL)
860                         {
861 #ifdef USE_CURSES
862                                 if(do_fullscreen)
863                                         display_disconnect(cep);
864 #endif
865 #ifdef I4B_EXTERNAL_MONITOR
866                                 monitor_evnt_disconnect(cep);
867 #endif
868                                 next_state(cep, EV_DRQ);
869                                 j++;                            
870                         }
871                     }
872                 }
873         }
874
875         if(j)
876         {
877                 llog(LL_DMN, "close_allactive: waiting for all connections terminated");
878                 sleep(5);
879         }
880 }
881
882 /*--------------------------------------------------------------------------*
883  *      set an interface up
884  *--------------------------------------------------------------------------*/
885 void
886 if_up(cfg_entry_t *cep)
887 {
888         msg_updown_ind_t mui;
889                         
890         /* set interface up */
891         
892         DBGL(DL_MSG, (llog(LL_DBG, "if_up: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
893         
894         mui.driver = cep->usrdevicename;
895         mui.driver_unit = cep->usrdeviceunit;
896         mui.updown = SOFT_ENA;
897                         
898         if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
899         {
900                 llog(LL_ERR, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
901                 error_exit(1, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
902         }
903         cep->down_retry_count = 0;
904
905 #ifdef USE_CURSES
906         if(do_fullscreen)
907                 display_updown(cep, 1);
908 #endif
909 #ifdef I4B_EXTERNAL_MONITOR
910         monitor_evnt_updown(cep, 1);
911 #endif
912         
913 }
914
915 /*--------------------------------------------------------------------------*
916  *      set an interface down
917  *--------------------------------------------------------------------------*/
918 void
919 if_down(cfg_entry_t *cep)
920 {
921         msg_updown_ind_t mui;
922                         
923         /* set interface up */
924         
925         DBGL(DL_MSG, (llog(LL_DBG, "if_down: taking %s%d down", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
926         
927         mui.driver = cep->usrdevicename;
928         mui.driver_unit = cep->usrdeviceunit;
929         mui.updown = SOFT_DIS;
930                         
931         if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
932         {
933                 llog(LL_ERR, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
934                 error_exit(1, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
935         }
936         cep->went_down_time = time(NULL);
937         cep->down_retry_count = 0;
938
939 #ifdef USE_CURSES
940         if(do_fullscreen)
941                 display_updown(cep, 0);
942 #endif
943 #ifdef I4B_EXTERNAL_MONITOR
944         monitor_evnt_updown(cep, 0);
945 #endif
946
947 }
948
949 /*--------------------------------------------------------------------------*
950  *      send a dial response to (an interface in) the kernel 
951  *--------------------------------------------------------------------------*/
952 void
953 dialresponse(cfg_entry_t *cep, int dstat)
954 {
955         msg_dialout_resp_t mdr;
956
957         static char *stattab[] = {
958                 "normal condition",
959                 "temporary failure",
960                 "permanent failure",
961                 "dialout not allowed"
962         };
963
964         if(dstat < DSTAT_NONE || dstat > DSTAT_INONLY)
965         {
966                 llog(LL_ERR, "dialresponse: dstat out of range %d!", dstat);
967                 return;
968         }
969         
970         mdr.driver = cep->usrdevicename;
971         mdr.driver_unit = cep->usrdeviceunit;
972         mdr.stat = dstat;
973         mdr.cause = cep->disc_cause;    
974         
975         if((ioctl(isdnfd, I4B_DIALOUT_RESP, &mdr)) < 0)
976         {
977                 llog(LL_ERR, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno));
978                 error_exit(1, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno));
979         }
980
981         DBGL(DL_DRVR, (llog(LL_DBG, "dialresponse: sent [%s]", stattab[dstat])));
982 }
983
984 /*--------------------------------------------------------------------------*
985  *      screening/presentation indicator
986  *--------------------------------------------------------------------------*/
987 void
988 handle_scrprs(int cdid, int scr, int prs, char *caller)
989 {
990         /* screening indicator */
991         
992         if(scr < SCR_NONE || scr > SCR_NET)
993         {
994                 llog(LL_ERR, "msg_connect_ind: invalid screening indicator value %d!", scr);
995         }
996         else
997         {
998                 static char *scrtab[] = {
999                         "no screening indicator",
1000                         "sreening user provided, not screened",
1001                         "screening user provided, verified & passed",
1002                         "screening user provided, verified & failed",
1003                         "screening network provided", };
1004
1005                 if(extcallattr)
1006                 {
1007                         llog(LL_CHD, "%05d %s %s", cdid, caller, scrtab[scr]);
1008                 }
1009                 else
1010                 {
1011                         DBGL(DL_MSG, (llog(LL_DBG, "%s - %s", caller, scrtab[scr])));
1012                 }
1013         }
1014                         
1015         /* presentation indicator */
1016         
1017         if(prs < PRS_NONE || prs > PRS_RESERVED)
1018         {
1019                 llog(LL_ERR, "msg_connect_ind: invalid presentation indicator value %d!", prs);
1020         }
1021         else
1022         {
1023                 static char *prstab[] = {
1024                         "no presentation indicator",
1025                         "presentation allowed",
1026                         "presentation restricted",
1027                         "number not available due to interworking",
1028                         "reserved presentation value" };
1029                         
1030                 if(extcallattr)
1031                 {
1032                         llog(LL_CHD, "%05d %s %s", cdid, caller, prstab[prs]);
1033                 }
1034                 else
1035                 {
1036                         DBGL(DL_MSG, (llog(LL_DBG, "%s - %s", caller, prstab[prs])));
1037                 }
1038         }
1039 }
1040
1041 /*--------------------------------------------------------------------------*
1042  *      check if the time is valid for an entry
1043  *--------------------------------------------------------------------------*/
1044 static int 
1045 isvalidtime(cfg_entry_t *cep)
1046 {
1047         time_t t;
1048         struct tm *tp;
1049
1050         if(cep->day == 0)
1051                 return(1);
1052
1053         t = time(NULL);
1054         tp = localtime(&t);
1055
1056         if(cep->day & HD)
1057         {
1058                 if(isholiday(tp->tm_mday, (tp->tm_mon)+1, (tp->tm_year)+1900))
1059                 {
1060                         DBGL(DL_VALID, (llog(LL_DBG, "isvalidtime: holiday %d.%d.%d", tp->tm_mday, (tp->tm_mon)+1, (tp->tm_year)+1900)));
1061                         goto dayok;
1062                 }
1063         }
1064         
1065         if(cep->day & (1 << tp->tm_wday))
1066         {
1067                 DBGL(DL_VALID, (llog(LL_DBG, "isvalidtime: day match")));       
1068                 goto dayok;
1069         }
1070
1071         return(0);
1072         
1073 dayok:
1074         if(cep->fromhr==0 && cep->frommin==0 && cep->tohr==0 && cep->tomin==0)
1075         {
1076                 DBGL(DL_VALID, (llog(LL_DBG, "isvalidtime: no time specified, match!")));
1077                 return(1);
1078         }
1079
1080         if(cep->tohr < cep->fromhr)
1081         {
1082                 /* before 00:00 */
1083                 
1084                 if( (tp->tm_hour > cep->fromhr) ||
1085                     (tp->tm_hour == cep->fromhr && tp->tm_min > cep->frommin) )
1086                 {
1087                         DBGL(DL_VALID, (llog(LL_DBG, "isvalidtime: t<f-1, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!",
1088                                 cep->fromhr, cep->frommin,
1089                                 cep->tohr, cep->tomin,
1090                                 tp->tm_hour, tp->tm_min)));
1091                         
1092                         return(1);
1093                 }
1094
1095                 /* after 00:00 */
1096                 
1097                 if( (tp->tm_hour < cep->tohr) ||
1098                     (tp->tm_hour == cep->tohr && tp->tm_min < cep->tomin) )
1099                 {
1100                         DBGL(DL_VALID, (llog(LL_DBG, "isvalidtime: t<f-2, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!",
1101                                 cep->fromhr, cep->frommin,
1102                                 cep->tohr, cep->tomin,
1103                                 tp->tm_hour, tp->tm_min)));
1104                         
1105                         return(1);
1106                 }
1107         }
1108         else if(cep->fromhr == cep->tohr)
1109         {
1110                 if(tp->tm_min >= cep->frommin && tp->tm_min < cep->tomin)
1111                 {
1112                         DBGL(DL_VALID, (llog(LL_DBG, "isvalidtime: f=t, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!",
1113                                 cep->fromhr, cep->frommin,
1114                                 cep->tohr, cep->tomin,
1115                                 tp->tm_hour, tp->tm_min)));
1116                         
1117                         return(1);
1118                 }
1119         }
1120         else
1121         {
1122                 if((tp->tm_hour > cep->fromhr && tp->tm_hour < cep->tohr) ||
1123                    (tp->tm_hour == cep->fromhr && tp->tm_min >= cep->frommin) ||
1124                    (tp->tm_hour == cep->tohr && tp->tm_min < cep->tomin) )
1125                 {
1126                         DBGL(DL_VALID, (llog(LL_DBG, "isvalidtime: t>f, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!",
1127                                 cep->fromhr, cep->frommin,
1128                                 cep->tohr, cep->tomin,
1129                                 tp->tm_hour, tp->tm_min)));
1130                         return(1);
1131                 }
1132         }
1133         DBGL(DL_VALID, (llog(LL_DBG, "isvalidtime: spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, no match!",
1134                         cep->fromhr, cep->frommin,
1135                         cep->tohr, cep->tomin,
1136                         tp->tm_hour, tp->tm_min)));
1137
1138         return(0);      
1139 }
1140
1141 /*--------------------------------------------------------------------------*
1142  *      prepend national or international prefix to a number
1143  *--------------------------------------------------------------------------*/
1144 int add_number_prefix(char *number, int type_of_number)
1145 {
1146         char tmp[TELNO_MAX];
1147         char *prefix;
1148         int result = 0;
1149
1150         if (type_of_number == TON_NATIONAL || type_of_number == TON_INTERNAT)
1151         {
1152                 if (type_of_number == TON_NATIONAL)
1153                         prefix = prefixnational;
1154                 else 
1155                         prefix = prefixinternational;
1156                 
1157                 /* Add prefix only if not already there */
1158                 if (strncmp(number, prefix, strlen(prefix)) != 0)
1159                 {
1160                         snprintf(tmp, sizeof(tmp)-1, "%s%s", prefix, number);
1161                         strncpy(number, tmp, TELNO_MAX-1);
1162                         result = 1;
1163                 }
1164         }
1165
1166         return result;
1167 }
1168
1169 /* EOF */