Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.bin / tip / libacu / unidialer.c
1 /*
2  * Copyright (c) 1986, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)unidialer.c      8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.bin/tip/libacu/unidialer.c,v 1.7 1999/08/28 01:06:30 peter Exp $
35  * $DragonFly: src/usr.bin/tip/libacu/unidialer.c,v 1.2 2003/06/17 04:29:32 dillon Exp $
36  */
37
38 /*
39  * Generalized routines for calling up on a Hayes AT command set based modem.
40  * Control variables are pulled out of a modem caps-style database to
41  * configure the driver for a particular modem.
42  */
43 #include "tipconf.h"
44 #include "tip.h"
45 #include "pathnames.h"
46
47 #include <sys/times.h>
48 #include <assert.h>
49 #include <err.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52
53 #include "acucommon.h"
54 #include "tod.h"
55
56 /* #define DEBUG */
57 #define MAXRETRY        5
58
59 typedef enum
60 {
61         mpt_notype, mpt_string, mpt_number, mpt_boolean
62 } modem_parm_type_t;
63
64 typedef struct {
65         modem_parm_type_t modem_parm_type;
66         const char *name;
67         union {
68                 char **string;
69                 unsigned int *number;
70         } value;
71         union {
72                 char *string;
73                 unsigned int number;
74         } default_value;
75 } modem_parm_t;
76
77 /*
78         Configuration
79 */
80 static char modem_name [80];
81 static char *dial_command;
82 static char *hangup_command;
83 static char *echo_off_command;
84 static char *reset_command;
85 static char *init_string;
86 static char *escape_sequence;
87 static int hw_flow_control;
88 static int lock_baud;
89 static unsigned int intercharacter_delay;
90 static unsigned int intercommand_delay;
91 static unsigned int escape_guard_time;
92 static unsigned int reset_delay;
93
94 static int unidialer_dialer (register char *num, char *acu);
95 static void unidialer_disconnect ();
96 static void unidialer_abort ();
97
98 static acu_t unidialer =
99 {
100         modem_name,
101         unidialer_dialer,
102         unidialer_disconnect,
103         unidialer_abort
104 };
105
106 /*
107         Table of parameters kept in modem database
108 */
109 modem_parm_t modem_parms [] = {
110         { mpt_string, "dial_command", &dial_command, "ATDT%s\r" },
111         { mpt_string, "hangup_command", &hangup_command, "ATH\r", },
112         { mpt_string, "echo_off_command", &echo_off_command, "ATE0\r" },
113         { mpt_string, "reset_command", &reset_command, "ATZ\r" },
114         { mpt_string, "init_string", &init_string, "AT&F\r", },
115         { mpt_string, "escape_sequence", &escape_sequence, "+++" },
116         { mpt_boolean, "hw_flow_control", (char **)&hw_flow_control, NULL },
117         { mpt_boolean, "lock_baud", (char **)&lock_baud, NULL },
118         { mpt_number, "intercharacter_delay", (char **)&intercharacter_delay, (char *)50 },
119         { mpt_number, "intercommand_delay", (char **)&intercommand_delay, (char *)300 },
120         { mpt_number, "escape_guard_time", (char **)&escape_guard_time, (char *)300 },
121         { mpt_number, "reset_delay", (char **)&reset_delay, (char *)3000 },
122         { mpt_notype, NULL, NULL, NULL }
123 };
124
125 /*
126         Forward declarations
127 */
128 static void unidialer_verbose_read ();
129 static void unidialer_modem_cmd (int fd, CONST char *cmd);
130 static void unidialer_write (int fd, CONST char *cp, int n);
131 static void unidialer_write_str (int fd, CONST char *cp);
132 static void unidialer_disconnect ();
133 static void sigALRM ();
134 static int unidialersync ();
135 static int unidialer_swallow (register char *match);
136
137 /*
138         Global vars
139 */
140 static int timeout = 0;
141 static int connected = 0;
142 static jmp_buf timeoutbuf, intbuf;
143
144 #define cgetflag(f)     (cgetcap(bp, f, ':') != NULL)
145
146 #ifdef DEBUG
147
148 #define print_str(x) printf (#x " = %s\n", x)
149 #define print_num(x) printf (#x " = %d\n", x)
150
151 void dumpmodemparms (char *modem)
152 {
153                 printf ("modem parms for %s\n", modem);
154                 print_str (dial_command);
155                 print_str (hangup_command);
156                 print_str (echo_off_command);
157                 print_str (reset_command);
158                 print_str (init_string);
159                 print_str (escape_sequence);
160                 print_num (lock_baud);
161                 print_num (intercharacter_delay);
162                 print_num (intercommand_delay);
163                 print_num (escape_guard_time);
164                 print_num (reset_delay);
165                 printf ("\n");
166 }
167 #endif
168
169 static int getmodemparms (const char *modem)
170 {
171         char *bp, *db_array [3], *modempath;
172         int ndx, stat;
173         modem_parm_t *mpp;
174
175         modempath = getenv ("MODEMS");
176
177         ndx = 0;
178
179         if (modempath != NULL)
180                 db_array [ndx++] = modempath;
181
182         db_array [ndx++] = _PATH_MODEMS;
183         db_array [ndx] = NULL;
184
185         if ((stat = cgetent (&bp, db_array, (char *)modem)) < 0) {
186                 switch (stat) {
187                 case -1:
188                         warnx ("unknown modem %s", modem);
189                         break;
190                 case -2:
191                         warnx ("can't open modem description file");
192                         break;
193                 case -3:
194                         warnx ("possible reference loop in modem description file");
195                         break;
196                 }
197                 return 0;
198         }
199         for (mpp = modem_parms; mpp->name; mpp++)
200         {
201                 switch (mpp->modem_parm_type)
202                 {
203                         case mpt_string:
204                                 if (cgetstr (bp, (char *)mpp->name, mpp->value.string) == -1)
205                                         *mpp->value.string = mpp->default_value.string;
206                                 break;
207
208                         case mpt_number:
209                         {
210                                 long l;
211                                 if (cgetnum (bp, (char *)mpp->name, &l) == -1)
212                                         *mpp->value.number = mpp->default_value.number;
213                                 else
214                                         *mpp->value.number = (unsigned int)l;
215                         }
216                                 break;
217
218                         case mpt_boolean:
219                                 *mpp->value.number = cgetflag ((char *)mpp->name);
220                                 break;
221                 }
222         }
223         strncpy (modem_name, modem, sizeof (modem_name) - 1);
224         modem_name [sizeof (modem_name) - 1] = '\0';
225         return 1;
226 }
227
228 /*
229 */
230 acu_t* unidialer_getmodem (const char *modem_name)
231 {
232         acu_t* rc = NOACU;
233         if (getmodemparms (modem_name))
234                 rc = &unidialer;
235         return rc;
236 }
237
238 static int unidialer_modem_ready ()
239 {
240 #ifdef TIOCMGET
241         int state;
242         ioctl (FD, TIOCMGET, &state);
243         return (state & TIOCM_DSR) ? 1 : 0;
244 #else
245         return (1);
246 #endif
247 }
248
249 static int unidialer_waitfor_modem_ready (int ms)
250 {
251 #ifdef TIOCMGET
252         int count;
253         for (count = 0; count < ms; count += 100)
254         {
255                 if (unidialer_modem_ready ())
256                 {
257 #ifdef DEBUG
258                         printf ("unidialer_waitfor_modem_ready: modem ready.\n");
259 #endif
260                         break;
261                 }
262                 acu_nap (100);
263         }
264         return (count < ms);
265 #else
266         acu_nap (250);
267         return (1);
268 #endif
269 }
270
271 int unidialer_tty_clocal (int flag)
272 {
273 #if HAVE_TERMIOS
274         struct termios t;
275         tcgetattr (FD, &t);
276         if (flag)
277                 t.c_cflag |= CLOCAL;
278         else
279                 t.c_cflag &= ~CLOCAL;
280         tcsetattr (FD, TCSANOW, &t);
281 #elif defined(TIOCMSET)
282         int state;
283         /*
284                 Don't have CLOCAL so raise CD in software to
285                 get the same effect.
286         */
287         ioctl (FD, TIOCMGET, &state);
288         if (flag)
289                 state |= TIOCM_CD;
290         else
291                 state &= ~TIOCM_CD;
292         ioctl (FD, TIOCMSET, &state);
293 #endif
294 }
295
296 int unidialer_get_modem_response (char *buf, int bufsz, int response_timeout)
297 {
298         sig_t f;
299         char c, *p = buf, *lid = buf + bufsz - 1;
300         int state;
301
302         assert (bufsz > 0);
303
304         f = signal (SIGALRM, sigALRM);
305
306         timeout = 0;
307
308         if (setjmp (timeoutbuf)) {
309                 signal (SIGALRM, f);
310                 *p = '\0';
311 #ifdef DEBUG
312                 printf ("get_response: timeout buf=%s, state=%d\n", buf, state);
313 #endif
314                 return (0);
315         }
316
317         ualarm (response_timeout * 1000, 0);
318
319         state = 0;
320
321         while (1)
322         {
323                 switch (state)
324                 {
325                         case 0:
326                                 if (read (FD, &c, 1) == 1)
327                                 {
328                                         if (c == '\r')
329                                         {
330                                                 ++state;
331                                         }
332                                         else
333                                         {
334 #ifdef DEBUG
335                                                 printf ("get_response: unexpected char %s.\n", ctrl (c));
336 #endif
337                                         }
338                                 }
339                                 break;
340
341                         case 1:
342                                 if (read (FD, &c, 1) == 1)
343                                 {
344                                         if (c == '\n')
345                                         {
346 #ifdef DEBUG
347                                                 printf ("get_response: <CRLF> encountered.\n", buf);
348 #endif
349                                                 ++state;
350                                         }
351                                         else
352                                         {
353                                                         state = 0;
354 #ifdef DEBUG
355                                                         printf ("get_response: unexpected char %s.\n", ctrl (c));
356 #endif
357                                         }
358                                 }
359                                 break;
360
361                         case 2:
362                                 if (read (FD, &c, 1) == 1)
363                                 {
364                                         if (c == '\r')
365                                                 ++state;
366                                         else if (c >= ' ' && p < lid)
367                                                 *p++ = c;
368                                 }
369                                 break;
370
371                         case 3:
372                                 if (read (FD, &c, 1) == 1)
373                                 {
374                                         if (c == '\n')
375                                         {
376                                                 signal (SIGALRM, f);
377                                                 /* ualarm (0, 0); */
378                                                 alarm (0);
379                                                 *p = '\0';
380 #ifdef DEBUG
381                                                 printf ("get_response: %s\n", buf);
382 #endif
383                                                 return (1);
384                                         }
385                                         else
386                                         {
387                                                 state = 0;
388                                                 p = buf;
389                                         }
390                                 }
391                                 break;
392                 }
393         }
394 }
395
396 int unidialer_get_okay (int ms)
397 {
398         int okay;
399         char buf [BUFSIZ];
400         okay = unidialer_get_modem_response (buf, sizeof (buf), ms) &&
401                 strcmp (buf, "OK") == 0;
402         return okay;
403 }
404
405 static int unidialer_dialer (register char *num, char *acu)
406 {
407         register char *cp;
408         char dial_string [80];
409 #if ACULOG
410         char line [80];
411 #endif
412         static int unidialer_connect(), unidialer_swallow();
413
414         #ifdef DEBUG
415         dumpmodemparms (modem_name);
416         #endif
417
418         if (lock_baud) {
419                 int i;
420                 if ((i = speed(number(value(BAUDRATE)))) == 0)
421                         return 0;
422                 ttysetup (i);
423         }
424
425         if (boolean(value(VERBOSE)))
426                 printf("Using \"%s\"\n", acu);
427
428         acu_hupcl ();
429
430         /*
431          * Get in synch.
432          */
433         if (!unidialersync()) {
434 badsynch:
435                 printf("tip: can't synchronize with %s\n", modem_name);
436 #if ACULOG
437                 logent(value(HOST), num, modem_name, "can't synch up");
438 #endif
439                 return (0);
440         }
441
442         unidialer_modem_cmd (FD, echo_off_command);     /* turn off echoing */
443
444         sleep(1);
445
446 #ifdef DEBUG
447         if (boolean(value(VERBOSE)))
448                 unidialer_verbose_read();
449 #endif
450
451         acu_flush (); /* flush any clutter */
452
453         unidialer_modem_cmd (FD, init_string);
454
455         if (!unidialer_get_okay (reset_delay))
456                 goto badsynch;
457
458         fflush (stdout);
459
460         for (cp = num; *cp; cp++)
461                 if (*cp == '=')
462                         *cp = ',';
463
464         (void) sprintf (dial_string, dial_command, num);
465
466         unidialer_modem_cmd (FD, dial_string);
467
468         connected = unidialer_connect ();
469
470         if (connected && hw_flow_control) {
471                 acu_hw_flow_control (hw_flow_control);
472         }
473
474 #if ACULOG
475         if (timeout) {
476                 sprintf(line, "%d second dial timeout",
477                         number(value(DIALTIMEOUT)));
478                 logent(value(HOST), num, modem_name, line);
479         }
480 #endif
481
482         if (timeout)
483                 unidialer_disconnect ();
484
485         return (connected);
486 }
487
488 static void unidialer_disconnect ()
489 {
490         int okay, retries;
491
492         acu_flush (); /* flush any clutter */
493
494         unidialer_tty_clocal (TRUE);
495
496         /* first hang up the modem*/
497         ioctl (FD, TIOCCDTR, 0);
498         acu_nap (250);
499         ioctl (FD, TIOCSDTR, 0);
500
501         /*
502          * If AT&D2, then dropping DTR *should* just hangup the modem. But
503          * some modems reset anyway; also, the modem may be programmed to reset
504          * anyway with AT&D3. Play it safe and wait for the full reset time before
505          * proceeding.
506          */
507         acu_nap (reset_delay);
508
509         if (!unidialer_waitfor_modem_ready (reset_delay))
510         {
511 #ifdef DEBUG
512                         printf ("unidialer_disconnect: warning CTS low.\r\n");
513 #endif
514         }
515
516         /*
517          * If not strapped for DTR control, try to get command mode.
518          */
519         for (retries = okay = 0; retries < MAXRETRY && !okay; retries++)
520         {
521                 int timeout_value;
522                 /* flush any clutter */
523                 if (!acu_flush ())
524                 {
525 #ifdef DEBUG
526                         printf ("unidialer_disconnect: warning flush failed.\r\n");
527 #endif
528                 }
529                 timeout_value = escape_guard_time;
530                 timeout_value += (timeout_value * retries / MAXRETRY);
531                 acu_nap (timeout_value);
532                 acu_flush (); /* flush any clutter */
533                 unidialer_modem_cmd (FD, escape_sequence);
534                 acu_nap (timeout_value);
535                 unidialer_modem_cmd (FD, hangup_command);
536                 okay = unidialer_get_okay (reset_delay);
537         }
538         if (!okay)
539         {
540                 #if ACULOG
541                 logent(value(HOST), "", modem_name, "can't hang up modem");
542                 #endif
543                 if (boolean(value(VERBOSE)))
544                         printf("hang up failed\n");
545         }
546         (void) acu_flush ();
547         close (FD);
548 }
549
550 static void unidialer_abort ()
551 {
552         unidialer_write_str (FD, "\r"); /* send anything to abort the call */
553         unidialer_disconnect ();
554 }
555
556 static void sigALRM ()
557 {
558         (void) printf("\07timeout waiting for reply\n");
559         timeout = 1;
560         longjmp(timeoutbuf, 1);
561 }
562
563 static int unidialer_swallow (register char *match)
564 {
565         sig_t f;
566         char c;
567
568         f = signal(SIGALRM, sigALRM);
569
570         timeout = 0;
571
572         if (setjmp(timeoutbuf)) {
573                 signal(SIGALRM, f);
574                 return (0);
575         }
576
577         alarm(number(value(DIALTIMEOUT)));
578
579         do {
580                 if (*match =='\0') {
581                         signal(SIGALRM, f);
582                         alarm (0);
583                         return (1);
584                 }
585                 do {
586                         read (FD, &c, 1);
587                 } while (c == '\0');
588                 c &= 0177;
589 #ifdef DEBUG
590                 if (boolean(value(VERBOSE)))
591                 {
592                         /* putchar(c); */
593                         printf (ctrl (c));
594                 }
595 #endif
596         } while (c == *match++);
597         signal(SIGALRM, SIG_DFL);
598         alarm(0);
599 #ifdef DEBUG
600         if (boolean(value(VERBOSE)))
601                 fflush (stdout);
602 #endif
603         return (0);
604 }
605
606 static struct baud_msg {
607         char *msg;
608         int baud;
609 } baud_msg[] = {
610         "",             B300,
611         " 1200",        B1200,
612         " 2400",        B2400,
613         " 9600",        B9600,
614         " 9600/ARQ",    B9600,
615         0,              0,
616 };
617
618 static int unidialer_connect ()
619 {
620         char c;
621         int nc, nl, n;
622         char dialer_buf[64];
623         struct baud_msg *bm;
624         sig_t f;
625
626         if (unidialer_swallow("\r\n") == 0)
627                 return (0);
628         f = signal(SIGALRM, sigALRM);
629 again:
630         nc = 0; nl = sizeof(dialer_buf)-1;
631         bzero(dialer_buf, sizeof(dialer_buf));
632         timeout = 0;
633         for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
634                 if (setjmp(timeoutbuf))
635                         break;
636                 alarm(number(value(DIALTIMEOUT)));
637                 n = read(FD, &c, 1);
638                 alarm(0);
639                 if (n <= 0)
640                         break;
641                 c &= 0x7f;
642                 if (c == '\r') {
643                         if (unidialer_swallow("\n") == 0)
644                                 break;
645                         if (!dialer_buf[0])
646                                 goto again;
647                         if (strcmp(dialer_buf, "RINGING") == 0 &&
648                             boolean(value(VERBOSE))) {
649 #ifdef DEBUG
650                                 printf("%s\r\n", dialer_buf);
651 #endif
652                                 goto again;
653                         }
654                         if (strncmp(dialer_buf, "CONNECT",
655                                     sizeof("CONNECT")-1) != 0)
656                                 break;
657                         if (lock_baud) {
658                                 signal(SIGALRM, f);
659 #ifdef DEBUG
660                                 if (boolean(value(VERBOSE)))
661                                         printf("%s\r\n", dialer_buf);
662 #endif
663                                 return (1);
664                         }
665                         for (bm = baud_msg ; bm->msg ; bm++)
666                                 if (strcmp(bm->msg, dialer_buf+sizeof("CONNECT")-1) == 0) {
667                                         if (!acu_setspeed (bm->baud))
668                                                 goto error;
669                                         signal(SIGALRM, f);
670 #ifdef DEBUG
671                                         if (boolean(value(VERBOSE)))
672                                                 printf("%s\r\n", dialer_buf);
673 #endif
674                                         return (1);
675                                 }
676                         break;
677                 }
678                 dialer_buf[nc] = c;
679         }
680 error1:
681         printf("%s\r\n", dialer_buf);
682 error:
683         signal(SIGALRM, f);
684         return (0);
685 }
686
687 /*
688  * This convoluted piece of code attempts to get
689  * the unidialer in sync.
690  */
691 static int unidialersync ()
692 {
693         int already = 0;
694         int len;
695         char buf[40];
696
697         while (already++ < MAXRETRY) {
698                 acu_nap (intercommand_delay);
699                 acu_flush (); /* flush any clutter */
700                 unidialer_write_str (FD, reset_command); /* reset modem */
701                 bzero(buf, sizeof(buf));
702                 acu_nap (reset_delay);
703                 ioctl (FD, FIONREAD, &len);
704                 if (len) {
705                         len = read(FD, buf, sizeof(buf));
706 #ifdef DEBUG
707                         buf [len] = '\0';
708                         printf("unidialersync (%s): (\"%s\")\n\r", modem_name, buf);
709 #endif
710                         if (index(buf, '0') ||
711                            (index(buf, 'O') && index(buf, 'K')))
712                                 return(1);
713                 }
714                 /*
715                  * If not strapped for DTR control,
716                  * try to get command mode.
717                  */
718                 acu_nap (escape_guard_time);
719                 unidialer_write_str (FD, escape_sequence);
720                 acu_nap (escape_guard_time);
721                 unidialer_write_str (FD, hangup_command);
722                 /*
723                  * Toggle DTR to force anyone off that might have left
724                  * the modem connected.
725                  */
726                 acu_nap (escape_guard_time);
727                 ioctl (FD, TIOCCDTR, 0);
728                 acu_nap (1000);
729                 ioctl (FD, TIOCSDTR, 0);
730         }
731         acu_nap (intercommand_delay);
732         unidialer_write_str (FD, reset_command);
733         return (0);
734 }
735
736 /*
737         Send commands to modem; impose delay between commands.
738 */
739 static void unidialer_modem_cmd (int fd, const char *cmd)
740 {
741         static struct timeval oldt = { 0, 0 };
742         struct timeval newt;
743         tod_gettime (&newt);
744         if (tod_lt (&newt, &oldt))
745         {
746                 unsigned int naptime;
747                 tod_subfrom (&oldt, newt);
748                 naptime = oldt.tv_sec * 1000 + oldt.tv_usec / 1000;
749                 if (naptime > intercommand_delay)
750                 {
751 #ifdef DEBUG
752                 printf ("unidialer_modem_cmd: suspicious naptime (%u ms)\r\n", naptime);
753 #endif
754                         naptime = intercommand_delay;
755                 }
756 #ifdef DEBUG
757                 printf ("unidialer_modem_cmd: delaying %u ms\r\n", naptime);
758 #endif
759                 acu_nap (naptime);
760         }
761         unidialer_write_str (fd, cmd);
762         tod_gettime (&oldt);
763         newt.tv_sec = 0;
764         newt.tv_usec = intercommand_delay;
765         tod_addto (&oldt, &newt);
766 }
767
768 static void unidialer_write_str (int fd, const char *cp)
769 {
770 #ifdef DEBUG
771         printf ("unidialer (%s): sending %s\n", modem_name, cp);
772 #endif
773         unidialer_write (fd, cp, strlen (cp));
774 }
775
776 static void unidialer_write (int fd, const char *cp, int n)
777 {
778         acu_nap (intercharacter_delay);
779         for ( ; n-- ; cp++) {
780                 write (fd, cp, 1);
781                 acu_nap (intercharacter_delay);
782         }
783 }
784
785 #ifdef DEBUG
786 static void unidialer_verbose_read()
787 {
788         int n = 0;
789         char buf[BUFSIZ];
790
791         if (ioctl(FD, FIONREAD, &n) < 0)
792                 return;
793         if (n <= 0)
794                 return;
795         if (read(FD, buf, n) != n)
796                 return;
797         write(1, buf, n);
798 }
799 #endif
800
801 /* end of unidialer.c */