home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / pcomm202 / part04 < prev    next >
Encoding:
Text File  |  1993-04-13  |  98.8 KB  |  4,260 lines

  1. Newsgroups: comp.sources.unix
  2. From: fthood!egray@uxc.cso.uiuc.edu (Emmet Gray)
  3. Subject: v26i156: pcomm-2.0.2 - a serial communications program (clone of ProComm), Part04/06
  4. Sender: unix-sources-moderator@vix.com
  5. Approved: paul@vix.com
  6.  
  7. Submitted-By: fthood!egray@uxc.cso.uiuc.edu (Emmet Gray)
  8. Posting-Number: Volume 26, Issue 156
  9. Archive-Name: pcomm-2.0.2/part04
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 4 (of 6)."
  18. # Contents:  Pcomm.1 curses.c di_win.c dial.c m_lib.c main.c vcs.c
  19. #   x_rcv.c x_send.c
  20. # Wrapped by vixie@gw.home.vix.com on Wed Apr 14 00:38:43 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'Pcomm.1' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'Pcomm.1'\"
  24. else
  25. echo shar: Extracting \"'Pcomm.1'\" \(9657 characters\)
  26. sed "s/^X//" >'Pcomm.1' <<'END_OF_FILE'
  27. X.\" use tbl and the man macro package
  28. X.if n .ds rq ""
  29. X.el .ds rq ''
  30. X.if n .ds lq ""
  31. X.el .ds lq ``
  32. X.TH pcomm L 
  33. X.SH NAME
  34. pcomm \- a telecommunication program
  35. X.SH SYNOPSIS
  36. X.B pcomm
  37. X[
  38. X.B \-d
  39. directory ] [
  40. X.B \-f
  41. system name ] [
  42. X.B \-a
  43. auxiliary file ] [
  44. X.B \-e
  45. X|
  46. X.B o
  47. X|
  48. X.B n
  49. X] [
  50. X.B -w
  51. word length ] [
  52. X.B -b
  53. baud rate ] [
  54. X.B -p
  55. phone number ]
  56. X.SH DESCRIPTION
  57. X.I Pcomm
  58. is a public domain telecommunication program for Unix that is designed
  59. to operate similarly to the MSDOS program, ProComm.  ProComm (TM) is
  60. copyrighted by Datastorm Technologies, Inc.
  61. X.PP
  62. The
  63. X.I \-d
  64. option is used to specify an additional path to search for the Pcomm
  65. support files.
  66. X.PP
  67. The
  68. X.I \-f
  69. option is used to specify automatic dialing of an entry in the dialing
  70. directory.  The
  71. X.I name
  72. field in the dialing directory is checked against the string given on
  73. the command line.  If a match is found, that entry is automatically
  74. dialed.
  75. X.PP
  76. The
  77. X.I \-a
  78. option is used to specify a script file to be \*(lqplayed\*(rq, the TTY
  79. to be used, or the modem to be used.
  80. X.PP
  81. The remaining options are used to set the parity, data bits, baud rate,
  82. and telephone number from the command line.  The normal method of
  83. dialing is from the dialing directory.
  84. X.PP
  85. X.RS 5
  86. X.B \-e
  87. X    Set the parity to even.
  88. X.br
  89. X.B \-o
  90. X    Set the parity to odd.
  91. X.br
  92. X.B \-n
  93. X    Set the parity to none.
  94. X.br
  95. X.B \-w
  96. X    Set the word length (number of data bits).
  97. X.br
  98. X.B \-b
  99. X    Set the baud rate.
  100. X.br
  101. X.B \-p
  102. X    Dial this phone number.
  103. X.RE
  104. X.PP
  105. Whenever
  106. X.I Pcomm
  107. is in the command mode, a status line is displayed at the bottom of the
  108. screen.  The eight fields of the status line are:
  109. X.PP
  110. X.RS 5
  111. X.nf
  112. X\(bu help screen command (or a temporary message)
  113. X\(bu name of the TTY device in use
  114. X\(bu duplex mode (FDX = full duplex, HDX = half duplex)
  115. X\(bu current line settings
  116. X\(bu status of data logging option
  117. X\(bu status of printer logging option
  118. X\(bu incoming CR translation
  119. X\(bu outgoing CR translation
  120. X.fi
  121. X.RE
  122. X.SH COMMANDS
  123. The following commands are accessible by pressing a user definable
  124. X\*(lqhot key\*(rq followed by a letter, number, or arrow key.  The
  125. default \*(lqhot key\*(rq is control-A.  The notation \*(lq^A-X\*(rq
  126. means control-A followed by the letter X. The dash (\-) is for clarity,
  127. and is not a part of the command sequence.
  128. X.TP
  129. X.B ^A-0
  130. Help Screen.  Display a brief review of the available commands.  Uses
  131. the number zero \*(lq0\*(rq not the letter \*(lqO\*(rq.
  132. X.TP
  133. X.B ^A-D
  134. Dialing Directory.  The dialing directory screen is used to display and
  135. maintain the database of phone number entries, and to select an entry
  136. for dialing.  To dial an entry, just enter the entry number at the
  137. prompt.  If the script field contains valid Unix shell script, that file
  138. is \*(lqplayed\*(rq, after the connection is made, to typically log the
  139. user on to the remote system.  See the Pcomm Reference Manual for the
  140. format and use of the script files.  The following commands are
  141. available from the dialing directory:
  142. X.RS 5
  143. X.TP
  144. X.B R
  145. Revise (or add) a dialing directory entry or a long distance dialing
  146. code.
  147. X.TP
  148. X.B P
  149. Print (display) the long distance dialing codes.
  150. X.TP
  151. X.B up/down
  152. Scroll the dialing directory up or down 10 lines.  Uses the up and down
  153. arrow keys.
  154. X.TP
  155. X.B M
  156. Manual dial.  Prompts for a phone number rather than using a number
  157. already in the dialing directory.
  158. X.TP
  159. X.B D
  160. Delete an entry or a range of entries.
  161. X.TP
  162. X.B L
  163. Print.  Send the dialing directory to the printer or a file of your
  164. choice.
  165. X.RE
  166. X.TP
  167. X.B ^A-R
  168. Automatic redial of selected dialing directory entries.  Prompts the
  169. user for a list of directory entries to be placed in the queue.
  170. X.I Pcomm
  171. will dial the numbers in a cycle until one of them answers.
  172. X.TP
  173. X.B ^A-M
  174. Allows the user to maintain a list of keyboard macros assigned to the
  175. shifted number keys.  When pressed, the string assigned to that key is
  176. sent to the remote system.
  177. X.TP
  178. X.B ^A-P
  179. Adjust the current communication line settings.  Display a menu of baud
  180. rate, parity, data bit, and stop bit choices.  Allows the new choice to
  181. be saved and become the default.  After dialing a remote, the line
  182. settings in the dialing directory entry are automatically used.  The
  183. current line settings are shown in the status line.
  184. X.TP
  185. X.B ^A-X
  186. XExit from
  187. X.I Pcomm.
  188. X.TP
  189. X.B ^A-4
  190. Spawn a Unix shell while still communicating with the remote system.
  191. Uses the \*(lqnative\*(rq shell as described in the SHELL environmental
  192. variable.
  193. X.TP
  194. X.B ^A-5
  195. Select a script file to be used to automate common keyboard input and
  196. to perform Pcomm command sequences.
  197. X.TP
  198. X.B ^A-I
  199. Display the program information screen.
  200. X.TP
  201. X.B ^A-S
  202. Display a choice of setup screens.  The following sub-menus are
  203. available:
  204. X.RS 5
  205. X.TP
  206. X.B 1
  207. TTY Setup.  This setup assigns the TTY ports that
  208. X.I Pcomm
  209. is allowed to use, and what is attached to each port.
  210. X.TP
  211. X.B 2
  212. Modem Setup.  The modem setup contains the commands to make the modem
  213. dial, hang up the phone, etc.
  214. X.TP
  215. X.B 3
  216. Terminal Setup.  The terminal setup contains the definition of the
  217. X\*(lqhot key\*(rq and the mapping of the end-of-line characters.
  218. X.TP
  219. X.B 4
  220. General Setup.  The general setup contains the default log file name,
  221. and the set of character synonyms.
  222. X.TP
  223. X.B 5
  224. ASCII Transfer Setup.  This setup screen contains additional character
  225. translations allowed during ASCII file transfers.
  226. X.TP
  227. X.B 6
  228. XExternal Protocol Setup.  This setup screen allows the user to embed the
  229. names of external file transfer programs into the list of available
  230. protocols.
  231. X.TP
  232. X.B S
  233. Save the changes to disk.
  234. X.RE
  235. X.TP
  236. X.B ^A-B
  237. Change the current working directory.
  238. X.TP
  239. X.B ^A-C
  240. Clear the local screen and home the cursor.
  241. X.TP
  242. X.B ^A-E
  243. Toggle the duplex mode from full to half, or from half to full.  The
  244. status line shows the current duplex mode.
  245. X.TP
  246. X.B ^A-H
  247. Hang up the phone.  Disconnect the phone, but remain in
  248. X.I Pcomm.
  249. X.TP
  250. X.B ^A-L
  251. Toggle the printer on and off.  Since the printer is accessed through
  252. the normal Unix spool program, the output is not sent to the printer
  253. until
  254. X.B after
  255. this feature is turned off.
  256. X.TP
  257. X.B ^A-3
  258. Toggle the incoming line termination characters between the carriage
  259. return and the carriage return line feed pair.  This affects the
  260. terminal session only, not the file transfers.  The current settings are
  261. shown in the status line.
  262. X.TP
  263. X.B ^A-7
  264. Send a modem break.  This is
  265. X.B not
  266. the same as the break key on the keyboard.
  267. X.TP
  268. X.B ^A-up
  269. Display a menu of file transfer protocols to be used to send files to a
  270. remote system.  Uses the up arrow key.
  271. X.TP
  272. X.B ^A-down
  273. Display file transfer protocols to be used to receive files from a
  274. remote system.  Uses the down arrow key.
  275. X.TP
  276. X.B ^A-F
  277. Display the contents of a Unix directory.
  278. X.TP
  279. X.B ^A-G
  280. Dump the contents of the screen to a specified file.  Special graphics
  281. characters may not be represented accurately in the file.
  282. X.TP
  283. X.B ^A-1
  284. Begin data logging.  Prompts the user for the name of the file that will
  285. be used to collect a complete record of the terminal session.
  286. X.TP
  287. X.B ^A-2
  288. Toggle the data logging option without prompting for a new file name.
  289. The status line shows the current data logging mode.
  290. X.SH "FILE TRANSFERS"
  291. X.I Pcomm
  292. understands the following file transfer protocols:
  293. X.PP
  294. X.RS 5
  295. X.TS
  296. l l l l 
  297. l l l l 
  298. X_ _ _ _
  299. l l l l.
  300. protocol    packet    error    multiple
  301. name    size    method    files?
  302. xmodem    128    checksum/CRC    no
  303. xmodem-1k    128/1024    checksum/CRC    no
  304. modem7    128    checksum    yes
  305. ymodem    128/1024    CRC    yes
  306. ymodem-g    128/1024    none    yes
  307. ASCII    none    none    no
  308. zmodem    128/1024    CRC    yes
  309. X(external)    ?    ?    ?
  310. X.TE
  311. X.RE
  312. X.PP
  313. X.I Pcomm
  314. can use an external program, such as Kermit or a proprietary program, to
  315. transfer files.  Commonly used external programs (such as zmodem in the
  316. example above) can have their names embedded into the list of available
  317. protocols.
  318. X.PP
  319. X.SH CONFIGURATION
  320. X.I Pcomm
  321. must have access to the terminfo or termcap data for the terminal being
  322. used.  The minimum capabilities include a screen size of at least 80
  323. columns by 24 lines and cursor movement capabilities.  Running
  324. X.I Pcomm
  325. from terminals at relatively slow speeds (i.e. 1200 baud) will cause the
  326. windows to appear sluggish.
  327. X.PP
  328. Terminals that don't have arrow keys or systems without the newer
  329. versions of curses(3) will require the user to substitute the letter
  330. X\*(lqU\*(rq for \*(lqup arrow\*(rq and \*(lqN\*(rq for \*(lqdown
  331. arrow\*(rq.
  332. X.PP
  333. There are four Pcomm support files that contain the dialing directory,
  334. the external file transfer programs, the modem/TTY database, and the
  335. start-up default parameters.  Users may maintain private versions of
  336. these files in a directory of their choice.
  337. X.I Pcomm
  338. also uses normal Unix shell scripts to perform the \*(lqchat\*(rq
  339. sequences necessary to automatically log a user onto a remote system.
  340. Scripts that invoke Pcomm commands require the use of the
  341. X.I Pcomm_cmd
  342. command.  See pcomm_cmd(1).
  343. X.I Pcomm
  344. uses the environmental variable PCOMM to search for the
  345. X\*(lqprivate\*(rq support files and script files.  The following
  346. directories are searched to find the files:
  347. X.PP
  348. X.RS 5
  349. X.nf
  350. X\(bu directory given with the \fI\-d\fP option
  351. X\(bu directory in the PCOMM environmental variable
  352. X\(bu current directory
  353. X\(bu default directory (compiled into Pcomm)
  354. X.fi
  355. X.RE
  356. X.PP
  357. The script field in the dialing directory serves two purposes.  The
  358. first use is to identify the shell script to use for automating command
  359. keyboard and command sequences.  The second use is to specify a TTY name
  360. for a given entry.  If the script is a valid device name, that device is
  361. used instead of searching the TTY database for a free port.
  362. X.SH FILES
  363. X.TS
  364. l l.
  365. pcomm.dial_dir    the dialing directory
  366. pcomm.extrnl    the external file transfer programs
  367. pcomm.modem    the modem/TTY database
  368. pcomm.param    the start-up default parameters
  369. X.TE
  370. X.SH "SEE ALSO"
  371. Pcomm Reference Manual, pcomm_cmd(1), waitfor(1), matches(1)
  372. END_OF_FILE
  373. if test 9657 -ne `wc -c <'Pcomm.1'`; then
  374.     echo shar: \"'Pcomm.1'\" unpacked with wrong size!
  375. fi
  376. # end of 'Pcomm.1'
  377. fi
  378. if test -f 'curses.c' -a "${1}" != "-c" ; then 
  379.   echo shar: Will not clobber existing file \"'curses.c'\"
  380. else
  381. echo shar: Extracting \"'curses.c'\" \(8961 characters\)
  382. sed "s/^X//" >'curses.c' <<'END_OF_FILE'
  383. X/*
  384. X * Miscellaneous curses(3) routines.
  385. X */
  386. X
  387. X#define STR_WIDTH    256
  388. X#define NUM_WIDTH    16
  389. X
  390. X#include <stdio.h>
  391. X#include <curses.h>
  392. X#include <signal.h>
  393. X#include "config.h"
  394. X#include "misc.h"
  395. X#include "status.h"
  396. X
  397. X#ifdef BSD
  398. X#include <setjmp.h>
  399. jmp_buf wk_buf;
  400. X#endif /* BSD */
  401. X
  402. X#ifndef OLDCURSES
  403. X#include <term.h>
  404. X#else /* OLDCURSES */
  405. X#ifdef UNIXPC
  406. X#include <sgtty.h>
  407. X#endif /* UNIXPC */
  408. X#endif /* OLDCURSES */
  409. X
  410. X/*
  411. X * Get a string from a window.  Similar to wgetstr(), except we limit
  412. X * the length, return a NULL (not pointer to NULL) on <ESC> key, beep
  413. X * at any character in "disallow" string, and beep at any character not
  414. X * in "allow". (It doesn't make sense to use both "allow" and "disallow"
  415. X * at the same time).  Returns a pointer to a static area.
  416. X */
  417. X
  418. char *
  419. get_str(win, num, allow, disallow)
  420. WINDOW *win;
  421. int num;
  422. char *allow, *disallow;
  423. X{
  424. X    int count, x, y;
  425. X    char ans, *strchr();
  426. X    static char buf[STR_WIDTH];
  427. X
  428. X    count = 0;
  429. X    while ((ans = wgetch(win)) != '\r') {
  430. X                    /* do our own backspace */
  431. X        if (ans == BS || ans == DEL) {
  432. X            if (!count) {
  433. X                beep();
  434. X                continue;
  435. X            }
  436. X            count--;
  437. X            buf[count] = '\0';
  438. X            getyx(win, y, x);
  439. X            x--;
  440. X            wmove(win, y, x);
  441. X            waddch(win, (chtype) ' ');
  442. X            wmove(win, y, x);
  443. X            wrefresh(win);
  444. X            continue;
  445. X        }
  446. X                    /* an <ESC> anywhere in the string */
  447. X        if (ans == ESC)
  448. X            return(NULL);
  449. X
  450. X                    /* illegal character? */
  451. X        if (*disallow != '\0' && strchr(disallow, ans)) {
  452. X            beep();
  453. X            continue;
  454. X        }
  455. X        if (*allow != '\0' && !strchr(allow, ans)) {
  456. X            beep();
  457. X            continue;
  458. X        }
  459. X                    /* exceeded the max? */
  460. X        if (count >= num || count >= STR_WIDTH) {
  461. X            beep();
  462. X            continue;
  463. X        }
  464. X
  465. X        buf[count] = ans;
  466. X        waddch(win, (chtype) ans);
  467. X        wrefresh(win);
  468. X        count++;
  469. X    }
  470. X    buf[count] = '\0';
  471. X    return(buf);
  472. X}
  473. X
  474. X/*
  475. X * Get a number from a window.  We limit the length and return a -1
  476. X * on <ESC> key.
  477. X */
  478. X
  479. int
  480. get_num(win, num)
  481. WINDOW *win;
  482. int num;
  483. X{
  484. X    int count, x, y, number;
  485. X    char ans, buf[NUM_WIDTH];
  486. X
  487. X    count = 0;
  488. X    while ((ans = wgetch(win)) != '\r') {
  489. X                    /* do our own backspace */
  490. X        if (ans == BS || ans == DEL) {
  491. X            if (!count) {
  492. X                beep();
  493. X                continue;
  494. X            }
  495. X            count--;
  496. X            buf[count] = '\0';
  497. X            getyx(win, y, x);
  498. X            x--;
  499. X            wmove(win, y, x);
  500. X            waddch(win, (chtype) ' ');
  501. X            wmove(win, y, x);
  502. X            wrefresh(win);
  503. X            continue;
  504. X        }
  505. X                    /* an <ESC> anywhere in the string */
  506. X        if (ans == ESC)
  507. X            return(-1);
  508. X                    /* only digits are allowed */
  509. X        if (ans < '0' || ans > '9') {
  510. X            beep();
  511. X            continue;
  512. X        }
  513. X                    /* exceeded the max? */
  514. X        if (count >= num || count >= NUM_WIDTH) {
  515. X            beep();
  516. X            continue;
  517. X        }
  518. X
  519. X        buf[count] = ans;
  520. X        waddch(win, (chtype) ans);
  521. X        wrefresh(win);
  522. X        count++;
  523. X    }
  524. X    buf[count] = '\0';
  525. X    number = atoi(buf);
  526. X    return(number);
  527. X}
  528. X
  529. X/*
  530. X * Change video attributes while printing a string.  The use of the
  531. X * pre-processor definition NOPROMOTE (located in config.h) means that
  532. X * strings will be printed without any special video attribute if the
  533. X * requested capability doesn't exist.
  534. X */
  535. X
  536. wattrstr(win, attr, str)
  537. WINDOW *win;
  538. chtype attr;
  539. char *str;
  540. X{
  541. X    int do_it;
  542. X                    /* if nothing, do nothing */
  543. X    if (str == NULL || *str == '\0')
  544. X        return(0);
  545. X
  546. X#ifdef OLDCURSES
  547. X    if (attr)
  548. X        wstandout(win);
  549. X    waddstr(win, str);
  550. X    if (attr)
  551. X        wstandend(win);
  552. X#else /* OLDCURSES */
  553. X
  554. X#ifdef NOPROMOTE
  555. X                    /* does the capability exist? */
  556. X    do_it = 0;
  557. X    if ((attr & A_STANDOUT) && enter_standout_mode)
  558. X        do_it++;
  559. X    if ((attr & A_UNDERLINE) && enter_underline_mode)
  560. X        do_it++;
  561. X    if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
  562. X        do_it++;
  563. X    if ((attr & A_BLINK) && enter_blink_mode)
  564. X        do_it++;
  565. X    if ((attr & A_BOLD) && enter_bold_mode)
  566. X        do_it++;
  567. X    if ((attr & A_DIM) && enter_dim_mode)
  568. X        do_it++;
  569. X#else /* NOPROMOTE */
  570. X    do_it = 1;
  571. X#endif /* NOPROMOTE */
  572. X
  573. X    if (do_it)
  574. X        wattron(win, attr);
  575. X                    /* print the string */
  576. X    waddstr(win, str);
  577. X    if (do_it)
  578. X        wattroff(win, attr);
  579. X#endif /* OLDCURSES */
  580. X    return(0);
  581. X}
  582. X
  583. X/*
  584. X * Change video attributes while printing a character.
  585. X */
  586. X
  587. wattrch(win, attr, c)
  588. WINDOW *win;
  589. chtype attr;
  590. char c;
  591. X{
  592. X    int do_it;
  593. X
  594. X    if (c == '\0')
  595. X        return(0);
  596. X#ifdef OLDCURSES
  597. X    if (attr)
  598. X        wstandout(win);
  599. X    waddch(win, (chtype) c);
  600. X    if (attr)
  601. X        wstandend(win);
  602. X#else /* OLDCURSES */
  603. X
  604. X#ifdef NOPROMOTE
  605. X                    /* does the capability exist? */
  606. X    do_it = 0;
  607. X    if ((attr & A_STANDOUT) && enter_standout_mode)
  608. X        do_it++;
  609. X    if ((attr & A_UNDERLINE) && enter_underline_mode)
  610. X        do_it++;
  611. X    if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
  612. X        do_it++;
  613. X    if ((attr & A_BLINK) && enter_blink_mode)
  614. X        do_it++;
  615. X    if ((attr & A_BOLD) && enter_bold_mode)
  616. X        do_it++;
  617. X    if ((attr & A_DIM) && enter_dim_mode)
  618. X        do_it++;
  619. X#else /* NOPROMOTE */
  620. X    do_it = 1;
  621. X#endif /* NOPROMOTE */
  622. X
  623. X    if (do_it)
  624. X        wattron(win, attr);
  625. X                    /* print the character */
  626. X    waddch(win, (chtype) c);
  627. X    if (do_it)
  628. X        wattroff(win, attr);
  629. X#endif /* OLDCURSES */
  630. X    return(0);
  631. X}
  632. X
  633. X
  634. X/*
  635. X * Change video attributes while printing a number.
  636. X */
  637. X
  638. wattrnum(win, attr, num)
  639. WINDOW *win;
  640. chtype attr;
  641. int num;
  642. X{
  643. X    int do_it;
  644. X    char buf[40];
  645. X
  646. X    sprintf(buf, "%d", num);
  647. X
  648. X#ifdef OLDCURSES
  649. X    if (attr)
  650. X        wstandout(win);
  651. X    waddstr(win, buf);
  652. X    if (attr)
  653. X        wstandend(win);
  654. X#else /* OLDCURSES */
  655. X
  656. X#ifdef NOPROMOTE
  657. X                    /* does the capability exist? */
  658. X    do_it = 0;
  659. X    if ((attr & A_STANDOUT) && enter_standout_mode)
  660. X        do_it++;
  661. X    if ((attr & A_UNDERLINE) && enter_underline_mode)
  662. X        do_it++;
  663. X    if ((attr & A_REVERSE) && (enter_reverse_mode || enter_standout_mode))
  664. X        do_it++;
  665. X    if ((attr & A_BLINK) && enter_blink_mode)
  666. X        do_it++;
  667. X    if ((attr & A_BOLD) && enter_bold_mode)
  668. X        do_it++;
  669. X    if ((attr & A_DIM) && enter_dim_mode)
  670. X        do_it++;
  671. X#else /* NOPROMOTE */
  672. X    do_it = 1;
  673. X#endif /* NOPROMOTE */
  674. X
  675. X    if (do_it)
  676. X        wattron(win, attr);
  677. X                    /* print the character */
  678. X    waddstr(win, buf);
  679. X    if (do_it)
  680. X        wattroff(win, attr);
  681. X#endif /* OLDCURSES */
  682. X    return(0);
  683. X}
  684. X
  685. X/*
  686. X * Prompt for a Yes or No answer.  Echo the single key input as words.
  687. X * Handle the funny cursor movement problems with magic cookie terminals.
  688. X * Returns a 1 on yes.
  689. X */
  690. X
  691. int
  692. yes_prompt(win, y, x, attr, str)
  693. WINDOW *win;
  694. int y, x;
  695. chtype attr;
  696. char *str;
  697. X{
  698. X    int ret_code, ans;
  699. X    char new_str[80], *strcpy(), *strcat();
  700. X                    /* sanity checking */
  701. X    if (strlen(str) > 71)
  702. X        *(str+71) = '\0';
  703. X                    /* build and display the prompt */
  704. X    strcpy(new_str, str);
  705. X    strcat(new_str, "? (y/n):");
  706. X    mvwattrstr(win, y, x, attr, new_str);
  707. X    wmove(win, y, strlen(new_str)+x+2);
  708. X    wrefresh(win);
  709. X        
  710. X    ret_code = -1;
  711. X    while (ret_code == -1) {
  712. X                    /* if inside a script */
  713. X        if (status->dup_fd != -1)
  714. X            ans = wait_key(win, 5);
  715. X        else
  716. X            ans = wgetch(win);
  717. X
  718. X        switch (ans) {
  719. X            case -1:
  720. X            case 'y':
  721. X            case 'Y':
  722. X                waddstr(win, "Yes");
  723. X                ret_code = 1;
  724. X                break;
  725. X            case 'n':
  726. X            case 'N':
  727. X            case ESC:
  728. X                waddstr(win, "No");
  729. X                ret_code = 0;
  730. X                break;
  731. X            default:
  732. X                beep();
  733. X
  734. X        }
  735. X    }
  736. X    wrefresh(win);
  737. X    return(ret_code);
  738. X}
  739. X
  740. X/*
  741. X * Handy routine for clear-to-end-of-line.  Fixes up the box if requested.
  742. X */
  743. X
  744. int
  745. clear_line(win, y, x, re_box)
  746. WINDOW *win;
  747. int y, x, re_box;
  748. X{
  749. X    if (wmove(win, y, x) == ERR)
  750. X        return(ERR);
  751. X
  752. X    wclrtoeol(win);
  753. X
  754. X    if (re_box) {
  755. X        mvwaddch(win, y, win->_maxx-1, (chtype) ACS_VLINE);
  756. X        wmove(win, y, x);
  757. X    }
  758. X    return(0);
  759. X}
  760. X
  761. X/*
  762. X * Routine to make a horizontal line.  Does NOT do a wrefresh().
  763. X */
  764. X
  765. int
  766. horizontal(win, x, y, len)
  767. WINDOW *win;
  768. int x, y, len;
  769. X{
  770. X    wmove(win, x, y);
  771. X
  772. X    while (len--)
  773. X        waddch(win, ACS_HLINE);
  774. X
  775. X    return(0);
  776. X}
  777. X
  778. X/*
  779. X * Wait for a key or time out.  Returns a -1 on timeout.  This is similar
  780. X * to the half-delay mode in the newer versions of curses(3).
  781. X */
  782. X
  783. static int wk_flag;
  784. static int wk_force();
  785. X
  786. X/* ARGSUSED */
  787. int
  788. wait_key(win, sec)
  789. WINDOW *win;
  790. unsigned int sec;
  791. X{
  792. X    int key;
  793. X    unsigned int alarm();
  794. X#ifdef WGETCH_BROKE
  795. X    char c;
  796. X#endif /* WGETCH_BROKE */
  797. X
  798. X    signal(SIGALRM, (SIG_TYPE(*) ()) wk_force);
  799. X    wk_flag = 0;
  800. X
  801. X    alarm(sec);
  802. X
  803. X#ifdef BSD
  804. X    if (setjmp(wk_buf))
  805. X        return(-1);
  806. X#endif /* BSD */
  807. X
  808. X#ifdef WGETCH_BROKE
  809. X    read(0, &c, 1);
  810. X    key = c & 0x7f;
  811. X#else /* WGETCH_BROKE */
  812. X    key = wgetch(win);
  813. X#endif /* WGETCH_BROKE */
  814. X
  815. X    if (wk_flag)
  816. X        return(-1);
  817. X    alarm(0);
  818. X    return(key);
  819. X}
  820. X
  821. X/* ARGSUSED */
  822. static int
  823. wk_force(dummy)
  824. int dummy;
  825. X{
  826. X#ifdef BSD
  827. X    longjmp(wk_buf, 1);
  828. X#else /* BSD */
  829. X    signal(SIGALRM, (SIG_TYPE(*) ()) wk_force);
  830. X    wk_flag = 1;
  831. X    return(0);
  832. X#endif /* BSD */
  833. X}
  834. X
  835. X/*
  836. X * Here are some routines that are probably missing from the older
  837. X * flavors of curses(3).
  838. X */
  839. X
  840. X#ifdef OLDCURSES
  841. X/*
  842. X * Make the terminal bell go off
  843. X */
  844. X
  845. int
  846. beep()
  847. X{
  848. X    fputc(BEL, stderr);
  849. X    return(0);
  850. X}
  851. X
  852. X/*
  853. X * Take the terminal out of the "curses mode".  The t_mode structure was 
  854. X * captured before we initialized the curses mode.
  855. X */
  856. X
  857. int
  858. resetterm()
  859. X{
  860. X    extern char _putchar();
  861. X    extern struct sgttyb t_mode;
  862. X
  863. X    ioctl(0, TIOCSETP, &t_mode);
  864. X    tputs(TE, 1, _putchar);
  865. X    tputs(VE, 1, _putchar);
  866. X    return(0);
  867. X}
  868. X
  869. X/*
  870. X * Put the terminal back into the "curses mode".  The c_mode structure was
  871. X * captured after we initialized the curses mode.
  872. X */
  873. X
  874. int
  875. fixterm()
  876. X{
  877. X    extern char _putchar();
  878. X    extern struct sgttyb c_mode;
  879. X
  880. X    ioctl(0, TIOCSETP, &c_mode);
  881. X    tputs(TI, 1, _putchar);
  882. X    tputs(VS, 1, _putchar);
  883. X    return(0);
  884. X}
  885. X#endif /* OLDCURSES */
  886. END_OF_FILE
  887. if test 8961 -ne `wc -c <'curses.c'`; then
  888.     echo shar: \"'curses.c'\" unpacked with wrong size!
  889. fi
  890. # end of 'curses.c'
  891. fi
  892. if test -f 'di_win.c' -a "${1}" != "-c" ; then 
  893.   echo shar: Will not clobber existing file \"'di_win.c'\"
  894. else
  895. echo shar: Extracting \"'di_win.c'\" \(9781 characters\)
  896. sed "s/^X//" >'di_win.c' <<'END_OF_FILE'
  897. X/*
  898. X * The dialing window routines.
  899. X */
  900. X
  901. X#include <stdio.h>
  902. X#include <curses.h>
  903. X#include "dial_dir.h"
  904. X#include "misc.h"
  905. X#include "modem.h"
  906. X#include "param.h"
  907. X#include "status.h"
  908. X
  909. static int can_sync();
  910. static void disp_queue();
  911. X
  912. X/*
  913. X * The dialing window.  Its job is to get a port, cycle thru the entries
  914. X * in the queue, while interpreting both the user's requests and the
  915. X * modem's responses.  A non-zero return code means we failed to connect.
  916. X */
  917. X
  918. int
  919. dial_win(repeat)
  920. int repeat;
  921. X{
  922. X    extern int fd;
  923. X    WINDOW *di_win, *newwin();
  924. X    int i, j, key, want_out, pass, tic;
  925. X    long now, time();
  926. X    char *tbuf, *ctime(), *str, cr=13, *read_codes();
  927. X    void dial_it(), delay_times();
  928. X    void error_win(), line_set(), hang_up(), vs_clear(), log_calls();
  929. X    unsigned int baud, sleep();
  930. X                    /* are we already talking? */
  931. X    hang_up(VERBOSE);
  932. X
  933. X    touchwin(stdscr);
  934. X    refresh();
  935. X
  936. X    /*
  937. X     * If the phone number points to NULL, then either you're on a
  938. X     * direct line, or you want to do the dialing yourself.
  939. X     */
  940. X    dir->d_cur = dir->q_num[0];
  941. X    if (*dir->number[dir->d_cur] == '\0') {
  942. X                    /* check LD permission */
  943. X        if (limit_ld(0))
  944. X            return(1);
  945. X
  946. X        if (get_port())
  947. X            return(1);
  948. X                    /* can't talk directly to OBM */
  949. X        if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
  950. X            error_win(0, "Can't access the On Board Modem directly",
  951. X             "You must use the automatic dialing feature");
  952. X            return(1);
  953. X        }
  954. X
  955. X        vs_clear(1);
  956. X        touchwin(stdscr);
  957. X        clear();
  958. X        printw("Connected to /dev/%s at %d baud...\n", modem->tty[modem->t_cur], dir->baud[0]);
  959. X        refresh();
  960. X                    /* We have to assume... */
  961. X        status->connected = 1;
  962. X        return(0);
  963. X    }
  964. X
  965. X    di_win = newwin(17, 70, 3, 5);
  966. X                    /* the basic window */
  967. X    mvwattrstr(di_win, 1, 20, A_BOLD, "D I A L I N G       W I N D O W");
  968. X    horizontal(di_win, 2, 0, 70);
  969. X    mvwaddstr(di_win, 4, 23, "System name:");
  970. X    mvwaddstr(di_win, 5, 23, "Pass number:");
  971. X    mvwaddstr(di_win, 6, 14, "Elapse time this try:");
  972. X    mvwaddstr(di_win, 7, 13, "Time at start of dial:");
  973. X    mvwaddstr(di_win, 8, 9, "Time at start of this try:");
  974. X    mvwaddstr(di_win, 9, 16, "Connect delay time:");
  975. X    mvwaddstr(di_win, 10, 17, "Redial delay time:");
  976. X    mvwaddstr(di_win, 11, 25, "Auxiliary:");
  977. X    mvwaddstr(di_win, 12, 16, "Result of last try:");
  978. X
  979. X    mvwaddstr(di_win, 14, 3, "<SPACE>: Recycle");
  980. X    mvwaddstr(di_win, 14, 22, "<DEL>: Remove from queue");
  981. X    mvwaddstr(di_win, 14, 49, "E: Change delays");
  982. X
  983. X                    /* the start time */
  984. X    time(&now);
  985. X    tbuf = ctime(&now);
  986. X    tbuf[19] = '\0';
  987. X    mvwaddstr(di_win, 7, 36, &tbuf[11]);
  988. X
  989. X    mvwprintw(di_win, 9, 36, "%-4d", param->c_delay);
  990. X    mvwprintw(di_win, 10, 36, "%-4d", param->r_delay);
  991. X
  992. X    box(di_win, VERT, HORZ);
  993. X    mvwaddstr(di_win, 16, 24, " Press <ESC> to abort ");
  994. X
  995. X    pass = 0;
  996. X    i = 0;
  997. X    want_out = 0;
  998. X    while (!want_out && pass <= repeat) {
  999. X        key = -1;
  1000. X        pass++;
  1001. X                    /* check LD permission */
  1002. X        if (limit_ld(i)) {
  1003. X            want_out++;
  1004. X            break;
  1005. X        }
  1006. X                    /* update the d_cur variable */
  1007. X        dir->d_cur = dir->q_num[i];
  1008. X
  1009. X                    /* get a port */
  1010. X        if (get_port()) {
  1011. X            want_out++;
  1012. X            break;
  1013. X        }
  1014. X                    /* fill in the window */
  1015. X        disp_queue(di_win, dir->d_cur, pass, now);
  1016. X        now = 0L;
  1017. X
  1018. X        /*
  1019. X         * The actual dial routine.  The "i" is the index into the
  1020. X         * queue, not the entry number.  Returns immediately without
  1021. X         * waiting for a carrier.
  1022. X         */
  1023. X        dial_it(i);
  1024. X        tty_flush(fd, 0);
  1025. X
  1026. X        /*
  1027. X         * Here we do a time-slice between reading the result codes
  1028. X         * from the modem and reading the keyboard.  The one second
  1029. X         * granularity won't be too accurate, but who cares?
  1030. X         */
  1031. X        tic = 0;
  1032. X        while (tic < param->c_delay) {
  1033. X            if ((str = read_codes(tic)) == NULL) {
  1034. X                mvwprintw(di_win, 6, 36, "%-4d", ++tic);
  1035. X                wrefresh(di_win);
  1036. X            }
  1037. X            else {
  1038. X                /*
  1039. X                 * A return code that converts to an number
  1040. X                 * that is less than 300 is probably an error
  1041. X                 * message.
  1042. X                 */
  1043. X                baud = (unsigned int) atoi(str);
  1044. X                if (baud < 300) {
  1045. X                    mvwprintw(di_win, 12, 36, "%-20.20s", str);
  1046. X                    wmove(di_win, 12, 36);
  1047. X                    wrefresh(di_win);
  1048. X                    break;
  1049. X                }
  1050. X                    /* we're connected */
  1051. X                beep();
  1052. X                clear_line(di_win, 12, 36, TRUE);
  1053. X                wattrstr(di_win, A_BLINK, "CONNECTED");
  1054. X                wmove(di_win, 12, 36);
  1055. X                wrefresh(di_win);
  1056. X                wait_key(di_win, 2);
  1057. X                delwin(di_win);
  1058. X
  1059. X                /*
  1060. X                 * Did the modem sync at a different baud
  1061. X                 * rate than what we expected?
  1062. X                 */
  1063. X                if (dir->baud[0] != baud) {
  1064. X                    if (can_sync(baud)) {
  1065. X                        dir->baud[0] = baud;
  1066. X                        line_set();
  1067. X                    }
  1068. X                }
  1069. X
  1070. X                vs_clear(1);
  1071. X                touchwin(stdscr);
  1072. X                clear();
  1073. X                printw("Connected to %s at %d baud...\n",
  1074. X                 dir->name[dir->d_cur], dir->baud[0]);
  1075. X                refresh();
  1076. X                status->connected = 1;
  1077. X
  1078. X                    /* log the call */
  1079. X                log_calls(i);
  1080. X                return(0);
  1081. X            }
  1082. X            if (tic == param->c_delay)
  1083. X                break;
  1084. X                    /* ok... try the keyboard */
  1085. X            if ((key = wait_key(di_win, 1)) != -1)
  1086. X                break;
  1087. X
  1088. X            mvwprintw(di_win, 6, 36, "%-4d", ++tic);
  1089. X            wrefresh(di_win);
  1090. X        }
  1091. X        /*
  1092. X         * If the modem did not return a code, then we need to
  1093. X         * stop it.  Sending a CR will stop most modems cold,
  1094. X         * except of course for the OBM...
  1095. X         */
  1096. X        if (str == NULL) {
  1097. X            if (!strcmp(modem->mname[modem->m_cur], "OBM"))
  1098. X                hang_up(QUIET);
  1099. X            else
  1100. X                write(fd, &cr, 1);
  1101. X            sleep(2);
  1102. X        }
  1103. X                    /* if we get here, no key was pressed */
  1104. X        if (key == -1) {
  1105. X            clear_line(di_win, 6, 14, TRUE);
  1106. X            mvwaddstr(di_win, 6, 27, "Pausing:");
  1107. X                    /* no return code? */
  1108. X            if (str == NULL) {
  1109. X                clear_line(di_win, 12, 36, TRUE);
  1110. X                waddstr(di_win, "TIMED OUT");
  1111. X                wmove(di_win, 12, 36);
  1112. X            }
  1113. X                    /* do the pause */
  1114. X            tic = 0;
  1115. X            while (tic < param->r_delay) {
  1116. X                if ((key = wait_key(di_win, 1)) != -1)
  1117. X                    break;
  1118. X                mvwprintw(di_win, 6, 36, "%-4d", ++tic);
  1119. X                wrefresh(di_win);
  1120. X            }
  1121. X            clear_line(di_win, 6, 14, TRUE);
  1122. X            waddstr(di_win, "Elapse time this try:");
  1123. X        }
  1124. X        mvwaddstr(di_win, 6, 36, "0   ");
  1125. X                    /* Process the keystroke */
  1126. X        switch (key) {
  1127. X            case ' ':    /* next in the queue */
  1128. X                clear_line(di_win, 12, 36, TRUE);
  1129. X                waddstr(di_win, "RECYCLED");
  1130. X                wmove(di_win, 12, 36);
  1131. X                wrefresh(di_win);
  1132. X                /* FALLTHRU */
  1133. X            case -1:    /* no key was pressed */
  1134. X                i++;
  1135. X                if (i > NUM_QUEUE)
  1136. X                    i = 0;
  1137. X                if (dir->q_num[i] == -1)
  1138. X                    i = 0;
  1139. X                break;
  1140. X            case DEL:    /* <DEL> key, remove from queue */
  1141. X                if (dir->q_num[1] == -1) {
  1142. X                    beep();
  1143. X                    clear_line(di_win, 12, 36, TRUE);
  1144. X                    waddstr(di_win, "NO MORE ENTRIES");
  1145. X                    wmove(di_win, 12, 36);
  1146. X                    wrefresh(di_win);
  1147. X                    wait_key(di_win, 3);
  1148. X                    break;
  1149. X                }
  1150. X                clear_line(di_win, 12, 36, TRUE);
  1151. X                waddstr(di_win, "ENTRY DELETED");
  1152. X                wmove(di_win, 12, 36);
  1153. X                wrefresh(di_win);
  1154. X                wait_key(di_win, 3);
  1155. X
  1156. X                    /* compact the queue */
  1157. X                for (j=i; j<NUM_QUEUE-1; j++)
  1158. X                    dir->q_num[j] = dir->q_num[j+1];
  1159. X                dir->q_num[NUM_QUEUE-1] = -1;
  1160. X
  1161. X                if (dir->q_num[i] == -1)
  1162. X                    i = 0;
  1163. X                break;
  1164. X            case 'e':
  1165. X            case 'E':    /* change delay time */
  1166. X                delay_times();
  1167. X                touchwin(di_win);
  1168. X                mvwprintw(di_win, 9, 36, "%-4d", param->c_delay);
  1169. X                mvwprintw(di_win, 10, 36, "%-4d", param->r_delay);
  1170. X                break;
  1171. X            case ESC:    /* <ESC> key */
  1172. X                beep();
  1173. X                clear_line(di_win, 12, 36, TRUE);
  1174. X                wattrstr(di_win, A_BLINK, "DIAL ABORTED");
  1175. X                wmove(di_win, 12, 36);
  1176. X                wrefresh(di_win);
  1177. X                wait_key(di_win, 3);
  1178. X                want_out++;
  1179. X                break;
  1180. X            default:
  1181. X                beep();
  1182. X                break;
  1183. X        }
  1184. X    }
  1185. X                    /* clean up and go home */
  1186. X    werase(di_win);
  1187. X    wrefresh(di_win);
  1188. X    delwin(di_win);
  1189. X    if (!want_out)
  1190. X        error_win(0, "Exceeded the maximum number of dialing attempts", "");
  1191. X    return(1);
  1192. X}
  1193. X
  1194. X/*
  1195. X * Display what info we know at this time.
  1196. X */
  1197. X
  1198. static void
  1199. disp_queue(win, entry, pass, first)
  1200. WINDOW *win;
  1201. int entry, pass;
  1202. long first;
  1203. X{
  1204. X    long now, time();
  1205. X    char *tbuf, *ctime();
  1206. X    void st_line();
  1207. X                    /* redo the status line */
  1208. X    st_line("");
  1209. X                    /* system name */
  1210. X    clear_line(win, 4, 36, TRUE);
  1211. X    waddstr(win, dir->name[entry]);
  1212. X                    /* pass number */
  1213. X    mvwprintw(win, 5, 36, "%-4d", pass);
  1214. X                    /* time of this call */
  1215. X    if (first)
  1216. X        now = first;
  1217. X    else
  1218. X        time(&now);
  1219. X
  1220. X    tbuf = ctime(&now);
  1221. X    tbuf[19] = '\0';
  1222. X    mvwaddstr(win, 8, 36, &tbuf[11]);
  1223. X                    /* the aux field */
  1224. X    clear_line(win, 11, 36, TRUE);
  1225. X    waddstr(win, dir->aux[entry]);
  1226. X
  1227. X    wmove(win, 12, 36);
  1228. X    wrefresh(win);
  1229. X    return;
  1230. X}
  1231. X
  1232. X/*
  1233. X * Determine if the modem can detect the synchronization of the connected
  1234. X * baud rate.  We check the modem database and see if the connect string
  1235. X * is unique.  A non-zero return code means the modem can sync.
  1236. X */
  1237. X
  1238. static int
  1239. can_sync(baud)
  1240. unsigned int baud;
  1241. X{
  1242. X    int i;
  1243. X    char *str;
  1244. X                    /* feature disabled? */
  1245. X    if (modem->auto_baud[modem->m_cur] != 'Y')
  1246. X        return(0);
  1247. X                    /* re-construct the string */
  1248. X    switch (baud) {
  1249. X        case 300:
  1250. X            str = modem->con_3[modem->m_cur];
  1251. X            break;
  1252. X        case 1200:
  1253. X            str = modem->con_12[modem->m_cur];
  1254. X            break;
  1255. X        case 2400:
  1256. X            str = modem->con_24[modem->m_cur];
  1257. X            break;
  1258. X        case 4800:
  1259. X            str = modem->con_48[modem->m_cur];
  1260. X            break;
  1261. X        case 7200:        /* not really the DTE speed */
  1262. X            if (modem->lock_sp[modem->t_cur])
  1263. X                return(1);
  1264. X            return(0);
  1265. X        case 9600:
  1266. X            str = modem->con_96[modem->m_cur];
  1267. X            break;
  1268. X        case 12000:        /* not really the DTE speed */
  1269. X            if (modem->lock_sp[modem->t_cur])
  1270. X                return(1);
  1271. X            return(0);
  1272. X        case 14400:        /* not really the DTE speed */
  1273. X            if (modem->lock_sp[modem->t_cur])
  1274. X                return(1);
  1275. X            return(0);
  1276. X        case 19200:
  1277. X            str = modem->con_192[modem->m_cur];
  1278. X            break;
  1279. X        case 38400:
  1280. X            str = modem->con_384[modem->m_cur];
  1281. X            break;
  1282. X        default:
  1283. X            return(0);
  1284. X    }
  1285. X
  1286. X    if (*str == '\0')
  1287. X        return(0);
  1288. X                    /* test "str" against all others */
  1289. X    i = 0;
  1290. X    if (!strcmp(str, modem->con_3[modem->m_cur]))
  1291. X        i++;
  1292. X    if (!strcmp(str, modem->con_12[modem->m_cur]))
  1293. X        i++;
  1294. X    if (!strcmp(str, modem->con_24[modem->m_cur]))
  1295. X        i++;
  1296. X    if (!strcmp(str, modem->con_48[modem->m_cur]))
  1297. X        i++;
  1298. X    if (!strcmp(str, modem->con_96[modem->m_cur]))
  1299. X        i++;
  1300. X    if (!strcmp(str, modem->con_192[modem->m_cur]))
  1301. X        i++;
  1302. X    if (!strcmp(str, modem->con_384[modem->m_cur]))
  1303. X        i++;
  1304. X                    /* should match only itself */
  1305. X    if (i == 1)
  1306. X        return(1);
  1307. X    return(0);
  1308. X}
  1309. END_OF_FILE
  1310. if test 9781 -ne `wc -c <'di_win.c'`; then
  1311.     echo shar: \"'di_win.c'\" unpacked with wrong size!
  1312. fi
  1313. # end of 'di_win.c'
  1314. fi
  1315. if test -f 'dial.c' -a "${1}" != "-c" ; then 
  1316.   echo shar: Will not clobber existing file \"'dial.c'\"
  1317. else
  1318. echo shar: Extracting \"'dial.c'\" \(9366 characters\)
  1319. sed "s/^X//" >'dial.c' <<'END_OF_FILE'
  1320. X/*
  1321. X * The routines that dial the modem and listen for the return codes.
  1322. X */
  1323. X
  1324. X#define HZ    60
  1325. X
  1326. X#include <stdio.h>
  1327. X#include <ctype.h>
  1328. X#include "config.h"
  1329. X#include "dial_dir.h"
  1330. X#include "misc.h"
  1331. X#include "modem.h"
  1332. X#include "param.h"
  1333. X
  1334. X#ifdef BSD
  1335. X#include <sys/time.h>
  1336. X#else /* BSD */
  1337. X#include <sys/types.h>
  1338. X#include <sys/times.h>
  1339. X#endif /* BSD */
  1340. X
  1341. X#ifdef UNIXPC
  1342. X#include <sys/phone.h>
  1343. X#endif /* UNIXPC */
  1344. X
  1345. static void do_pause();
  1346. static int match();
  1347. X
  1348. X/*
  1349. X * Get the dial string ready, send it to the modem.  The parameter is not
  1350. X * the actual entry number, it is an index into the queue.
  1351. X */
  1352. X
  1353. void
  1354. dial_it(num)
  1355. int num;
  1356. X{
  1357. X    int i, skip;
  1358. X    char s[100], number[40], *strcpy(), *strcat(), *n, *strchr();
  1359. X    void send_str();
  1360. X#ifdef UNIXPC
  1361. X    extern int fd;
  1362. X    struct updata pbuf;
  1363. X    unsigned int sleep();
  1364. X#endif /* UNIXPC */
  1365. X
  1366. X    /*
  1367. X     * Create the string to be sent to the modem.  The long distance
  1368. X     * codes are added if they are requested.
  1369. X     */
  1370. X    s[0] = '\0';
  1371. X    strcpy(s, modem->dial[modem->m_cur]);
  1372. X
  1373. X    switch (dir->q_ld[num]) {
  1374. X        case 0:            /* no ld code requested */
  1375. X            break;
  1376. X        case '+':
  1377. X            strcat(s, param->ld_plus);
  1378. X            break;
  1379. X        case '-':
  1380. X            strcat(s, param->ld_minus);
  1381. X            break;
  1382. X        case '@':
  1383. X            strcat(s, param->ld_at);
  1384. X            break;
  1385. X        case '#':
  1386. X            strcat(s, param->ld_pound);
  1387. X            break;
  1388. X    }
  1389. X    /*
  1390. X     * Purify the phone number by removing all the pretty characters
  1391. X     * that don't need to be sent to the modem.  Typically the "-",
  1392. X     * "(", ")", and space characters are just for looks.  To prevent
  1393. X     * this action, prepend a "\" to the character.
  1394. X     */
  1395. X    i = 0;
  1396. X    skip = 0;
  1397. X    n = dir->number[dir->q_num[num]];
  1398. X    while (*n) {
  1399. X        if (*n == '\\' && !skip) {
  1400. X            skip++;
  1401. X            n++;
  1402. X            continue;
  1403. X        }
  1404. X        if (!strchr("-() ", *n) || skip)
  1405. X            number[i++] = *n;
  1406. X        n++;
  1407. X        skip = 0;
  1408. X    }
  1409. X    number[i] = '\0';
  1410. X                    /* add it to the string */
  1411. X    strcat(s, number);
  1412. X    strcat(s, modem->suffix[modem->m_cur]);
  1413. X#ifdef DEBUG
  1414. X    fprintf(stderr, "raw dial string: \"%s\"\n", s);
  1415. X#endif /* DEBUG */
  1416. X
  1417. X#ifdef UNIXPC
  1418. X                    /* special case for OBM */
  1419. X    if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
  1420. X                    /* prepare the modem */
  1421. X        pbuf.c_lineparam = DATA|DTMF;
  1422. X        pbuf.c_waitdialtone = 5;
  1423. X        pbuf.c_linestatus = 0;
  1424. X        pbuf.c_feedback = SPEAKERON|NORMSPK;
  1425. X        pbuf.c_waitflash = 500;
  1426. X        ioctl(fd, PIOCSETP, &pbuf);
  1427. X        sleep(1);
  1428. X                    /* connect the dialer */
  1429. X        ioctl(fd, PIOCRECONN);
  1430. X        sleep(2);
  1431. X                    /* dial each digit */
  1432. X        n = s;
  1433. X        while (*n) {
  1434. X                    /* switch tone/pulse dialing? */
  1435. X            switch (*n) {
  1436. X                case '^':
  1437. X                    pbuf.c_lineparam = DATA|PULSE;
  1438. X                    ioctl(fd, PIOCSETP, &pbuf);
  1439. X                    break;
  1440. X                case '%':
  1441. X                    pbuf.c_lineparam = DATA|DTMF;
  1442. X                    ioctl(fd, PIOCSETP, &pbuf);
  1443. X                    break;
  1444. X                default:
  1445. X                    ioctl(fd, PIOCDIAL, n);
  1446. X                    break;
  1447. X            }
  1448. X            n++;
  1449. X        }
  1450. X        /*
  1451. X         * It seems that the OBM doesn't always talk reliably to
  1452. X         * other types of modems (most notibly Telebits).  Here
  1453. X         * is some witchcraft to fix the problem.
  1454. X         */
  1455. X        ioctl(fd, PIOCOVSPD);
  1456. X        return;
  1457. X    }
  1458. X#endif /* UNIXPC */
  1459. X
  1460. X    send_str(s, SLOW);
  1461. X    return;
  1462. X}
  1463. X
  1464. X/*
  1465. X * Send a string to the modem.  Performs all the character synonym
  1466. X * translations.
  1467. X */
  1468. X
  1469. void
  1470. send_str(s, slow)
  1471. char *s;
  1472. int slow;
  1473. X{
  1474. X    extern int fd;
  1475. X    int skip, has_pause;
  1476. X    char *strchr();
  1477. X    unsigned int sleep();
  1478. X                    /* empty string? */
  1479. X    if (s == NULL || *s == '\0')
  1480. X        return;
  1481. X
  1482. X                    /* contains a pause? */
  1483. X    has_pause = 0;
  1484. X    if (strchr(s, '~'))
  1485. X        has_pause++;
  1486. X
  1487. X    tty_flush(fd, 1);
  1488. X    /*
  1489. X     * Change the character synonyms to their real values.  Writes
  1490. X     * the characters to the modem.  To remove the special meaning
  1491. X     * of one of the characters, prepend a "\" to it.
  1492. X     */
  1493. X    skip = 0;
  1494. X    while (*s) {
  1495. X                    /* send the literal character */
  1496. X        if (skip) {
  1497. X            skip = 0;
  1498. X            write(fd, s, 1);
  1499. X            if (has_pause || slow)
  1500. X                tty_drain(fd);
  1501. X            if (slow)
  1502. X                do_pause();
  1503. X#ifdef DEBUG
  1504. X            fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
  1505. X#endif /* DEBUG */
  1506. X            s++;
  1507. X            continue;
  1508. X        }
  1509. X                    /* turn off the special meaning */
  1510. X        if (*s == '\\') {
  1511. X            skip++;
  1512. X            s++;
  1513. X            continue;
  1514. X        }
  1515. X                    /* pause synonym */
  1516. X        if (*s == param->pause_char) {
  1517. X            sleep(1);
  1518. X            s++;
  1519. X            continue;
  1520. X        }
  1521. X                    /* carriage return synonym */
  1522. X        if (*s == param->cr_char)
  1523. X            *s = '\r';
  1524. X                    /* 2 character control sequence */
  1525. X        if (*s == param->ctrl_char) {
  1526. X            s++;
  1527. X                    /* premature EOF? */
  1528. X            if (*s == '\0')
  1529. X                break;
  1530. X                    /* upper and lower case */
  1531. X            if (*s > '_')
  1532. X                *s -= 96;
  1533. X            else
  1534. X                *s -= 64;
  1535. X        }
  1536. X                    /* escape synonym */
  1537. X        if (*s == param->esc_char)
  1538. X            *s = ESC;
  1539. X                    /* modem break synonym */
  1540. X        if (*s == param->brk_char) {
  1541. X            tty_break(fd);
  1542. X            sleep(1);
  1543. X            s++;
  1544. X            continue;
  1545. X        }
  1546. X
  1547. X        write(fd, s, 1);
  1548. X#ifdef DEBUG
  1549. X        fprintf(stderr, "send_str: \"%c\", %02x, %03o, %d\n", *s, *s, *s, *s);
  1550. X#endif /* DEBUG */
  1551. X        /*
  1552. X         * Because the pause char makes the timing critical, we
  1553. X         * wait until the buffer is clear before we continue.
  1554. X         */
  1555. X        if (has_pause || slow)
  1556. X            tty_drain(fd);
  1557. X        if (slow)
  1558. X            do_pause();
  1559. X        s++;
  1560. X    }
  1561. X    return;
  1562. X}
  1563. X
  1564. X/*
  1565. X * Read the result codes coming back from the modem.  Test for the 7
  1566. X * "connect" strings and the 4 "no connect" strings.  Return the connected
  1567. X * baud rate (as a string) or the error message.
  1568. X */
  1569. X
  1570. char *
  1571. read_codes(tic)
  1572. int tic;
  1573. X{
  1574. X    int i, j, k;
  1575. X    char c;
  1576. X    static char rc_buf[512];
  1577. X    static int rc_index;
  1578. X#ifdef UNIXPC
  1579. X    extern int fd;
  1580. X    unsigned int sleep();
  1581. X    struct updata pbuf;
  1582. X                    /* special case for OBM */
  1583. X    if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
  1584. X        ioctl(fd, PIOCGETP, &pbuf);
  1585. X
  1586. X        /*
  1587. X         * The OBM doesn't use a return message to announce the
  1588. X         * connection to a remote, so we fake one.  The 1200
  1589. X         * is quite arbitrary... it is not an indicator of the
  1590. X         * connected baud rate.
  1591. X         */
  1592. X        if (pbuf.c_linestatus & MODEMCONNECTED)
  1593. X            return("1200");
  1594. X
  1595. X        sleep(1);
  1596. X        return(NULL);
  1597. X    }
  1598. X#endif /* UNIXPC */
  1599. X    if (tic == 0)
  1600. X        rc_index = 0;
  1601. X                    /* search for key words */
  1602. X    for (; rc_index<511; rc_index++) {
  1603. X        if ((i = getc_line(1)) <= 0)
  1604. X            return(NULL);
  1605. X
  1606. X        c = i & 0x7f;
  1607. X#ifdef DEBUG
  1608. X        fprintf(stderr, "read_codes: \"%c\", %02x, %03o, %d\n", c, c, c, c);
  1609. X#endif /* DEBUG */
  1610. X                    /* no NULLs please */
  1611. X        if (c == '\0') {
  1612. X            if (rc_index)
  1613. X                rc_index--;
  1614. X            continue;
  1615. X        }
  1616. X        rc_buf[rc_index] = c;
  1617. X        rc_buf[rc_index+1] = '\0';
  1618. X                    /* the connect strings */
  1619. X        if (match(rc_buf, modem->con_3[modem->m_cur]))
  1620. X            return("300");
  1621. X
  1622. X        if (match(rc_buf, modem->con_12[modem->m_cur]))
  1623. X            return("1200");
  1624. X
  1625. X        if (match(rc_buf, modem->con_24[modem->m_cur]))
  1626. X            return("2400");
  1627. X
  1628. X        if (match(rc_buf, modem->con_48[modem->m_cur]))
  1629. X            return("4800");
  1630. X
  1631. X        if (match(rc_buf, modem->con_96[modem->m_cur]))
  1632. X            return("9600");
  1633. X
  1634. X        if (match(rc_buf, modem->con_192[modem->m_cur]))
  1635. X            return("19200");
  1636. X
  1637. X        if (match(rc_buf, modem->con_384[modem->m_cur]))
  1638. X            return("38400");
  1639. X
  1640. X                    /* the no connect strings */
  1641. X        if (match(rc_buf, modem->no_con1[modem->m_cur]))
  1642. X            return(modem->no_con1[modem->m_cur]);
  1643. X
  1644. X        if (match(rc_buf, modem->no_con2[modem->m_cur]))
  1645. X            return(modem->no_con2[modem->m_cur]);
  1646. X
  1647. X        if (match(rc_buf, modem->no_con3[modem->m_cur]))
  1648. X            return(modem->no_con3[modem->m_cur]);
  1649. X
  1650. X        if (match(rc_buf, modem->no_con4[modem->m_cur]))
  1651. X            return(modem->no_con4[modem->m_cur]);
  1652. X        /*
  1653. X         * OK.. this is the tricky part.  What if the modem returns
  1654. X         * the connected rate (in lieu of the DTE rate)?  For
  1655. X         * example, the message is "CONNECT 14400", but the DTE
  1656. X         * is locked at 38400.
  1657. X         */
  1658. X        if (modem->lock_sp[modem->t_cur]) {
  1659. X            for (j=0; j<512; j++) {
  1660. X                if (rc_buf[j] == '\0')
  1661. X                    break;
  1662. X                if (isdigit(rc_buf[j])) {
  1663. X                    k = atoi(&rc_buf[j]);
  1664. X                    switch(k) {
  1665. X                        case 7200:
  1666. X                            return("7200");
  1667. X                        case 12000:
  1668. X                            return("12000");
  1669. X                        case 14400:
  1670. X                            return("14400");
  1671. X                    }
  1672. X                    break;
  1673. X                }
  1674. X            }
  1675. X        }
  1676. X                    
  1677. X    }
  1678. X                    /* ran out of buffer? */
  1679. X    return("ERROR");
  1680. X}
  1681. X
  1682. X/*
  1683. X * Test for a match between two character strings.  A non-zero return code
  1684. X * means that s2 was found at the end of s1.
  1685. X */
  1686. X
  1687. static int
  1688. match(s1, s2)
  1689. char *s1, *s2;
  1690. X{
  1691. X    register int i;
  1692. X    int skip, diff;
  1693. X    char new[40];
  1694. X                    /* if no string to match */
  1695. X    if (*s2 == '\0')
  1696. X        return(0);
  1697. X                    /* translate synonyms */
  1698. X    i = 0;
  1699. X    skip = 0;
  1700. X    while (*s2) {
  1701. X                    /* literal character */
  1702. X        if (skip) {
  1703. X            skip = 0;
  1704. X            new[i++] = *s2;
  1705. X            s2++;
  1706. X            continue;
  1707. X        }
  1708. X                    /* turn off the special meaning */
  1709. X        if (*s2 == '\\') {
  1710. X            skip++;
  1711. X            s2++;
  1712. X            continue;
  1713. X        }
  1714. X                    /* carriage return synonym */
  1715. X        if (*s2 == param->cr_char)
  1716. X            *s2 = '\r';
  1717. X
  1718. X                    /* 2 character control sequence */
  1719. X        if (*s2 == param->ctrl_char) {
  1720. X            s2++;
  1721. X            if (*s2 == '\0')
  1722. X                break;
  1723. X            if (*s2 > '_')
  1724. X                *s2 -= 96;
  1725. X            else
  1726. X                *s2 -= 64;
  1727. X        }
  1728. X                    /* escape synonym */
  1729. X        if (*s2 == param->esc_char)
  1730. X            *s2 = ESC;
  1731. X
  1732. X        new[i++] = *s2;
  1733. X        s2++;
  1734. X    }
  1735. X    new[i] = '\0';
  1736. X
  1737. X    diff = strlen(s1) - strlen(new);
  1738. X                    /* is it possible? */
  1739. X    if (diff < 0)
  1740. X        return(0);
  1741. X                    /* test it out */
  1742. X    if (!strcmp(&s1[diff], new))
  1743. X        return(1);
  1744. X    return(0);
  1745. X}
  1746. X
  1747. X/*
  1748. X * Apparently some modems can't take input at the rated speed while
  1749. X * in the command mode.  Therefore, a 0.10 sec pause a required between
  1750. X * characters.
  1751. X */
  1752. X
  1753. static void
  1754. do_pause()
  1755. X{
  1756. X#ifdef HAVE_USLEEP
  1757. X    usleep(100000);
  1758. X#else /* HAVE_USLEEP */
  1759. X                /* Hey! I know these routines are a hack */
  1760. X#ifdef BSD
  1761. X    struct timeval tv;
  1762. X    struct timezone tz;
  1763. X    double t1;
  1764. X
  1765. X    gettimeofday(&tv, &tz);
  1766. X    t1 = tv.tv_sec + (tv.tv_usec / 1000000.0);
  1767. X    do
  1768. X        gettimeofday(&tv, &tz);
  1769. X    while ((tv.tv_sec + (tv.tv_usec / 1000000.0) - t1) < 0.1);
  1770. X#else /* BSD */
  1771. X    struct tms t;
  1772. X    long t1;
  1773. X
  1774. X    t1 = times(&t);
  1775. X    while ((times(&t) - t1) < HZ/10)
  1776. X        ;
  1777. X#endif /* BSD */
  1778. X#endif /* HAVE_USLEEP */
  1779. X    return;
  1780. X}
  1781. END_OF_FILE
  1782. if test 9366 -ne `wc -c <'dial.c'`; then
  1783.     echo shar: \"'dial.c'\" unpacked with wrong size!
  1784. fi
  1785. # end of 'dial.c'
  1786. fi
  1787. if test -f 'm_lib.c' -a "${1}" != "-c" ; then 
  1788.   echo shar: Will not clobber existing file \"'m_lib.c'\"
  1789. else
  1790. echo shar: Extracting \"'m_lib.c'\" \(10182 characters\)
  1791. sed "s/^X//" >'m_lib.c' <<'END_OF_FILE'
  1792. X/*
  1793. X * Routines to manipulate the pcomm.modem file
  1794. X */
  1795. X
  1796. X#include <stdio.h>
  1797. X#include "modem.h"
  1798. X
  1799. X/*
  1800. X * Read the modem/TTY database file.  Returns a pointer to a static area
  1801. X * containing the MODEM structure.  All modem entries and all TTY entries
  1802. X * are created regardless of the number of physical entries in the file.
  1803. X */
  1804. X
  1805. struct MODEM *
  1806. read_modem()
  1807. X{
  1808. X    extern char *null_ptr;
  1809. X    FILE *fp, *uid_fopen();
  1810. X    int i, tty, mod, line, oops, m_line, start, stop;
  1811. X    char *str_dup(), buf[200], message[80], token[40], *str_tok(), *str;
  1812. X    char *temp_token, *t_sep, *m_sep, *m_letter, *findfile();
  1813. X    static struct MODEM m;
  1814. X    void error_win();
  1815. X
  1816. X    if ((m.m_path = findfile("pcomm.modem")) == NULL)
  1817. X        error_win(1, "Support file \"pcomm.modem\" is missing", "or no read permission");
  1818. X
  1819. X    if (!(fp = uid_fopen(m.m_path, "r"))) {
  1820. X        sprintf(buf, "\"%s\" for read", m.m_path);
  1821. X        error_win(1, "Can't open modem/TTY file", buf);
  1822. X    }
  1823. X
  1824. X    t_sep = ";;\n";
  1825. X    m_sep = ";;;;\n;;;;;;;\n;;;\n";
  1826. X    m_letter = "abc";
  1827. X    oops = 0;
  1828. X    tty = 0;
  1829. X    mod = 0;
  1830. X    line = 0;
  1831. X    m_line = 0;
  1832. X    while (fgets(buf, 200, fp) != NULL) {
  1833. X        line++;
  1834. X        if (tty > NUM_TTY || mod > NUM_MODEM)
  1835. X            break;
  1836. X                    /* get the token */
  1837. X        if (!(temp_token = str_tok(buf, '='))) {
  1838. X            sprintf(message, "is missing a token at line %d", line);
  1839. X            oops++;
  1840. X            break;
  1841. X        }
  1842. X        if (*temp_token != 'T' && *temp_token != 'M') {
  1843. X            sprintf(message, "is corrupted at line %d", line);
  1844. X            oops++;
  1845. X            break;
  1846. X        }
  1847. X                    /* the TTY database */
  1848. X        if (*temp_token == 'T') {
  1849. X            /*
  1850. X             * This is similar to the "real" strtok() command
  1851. X             * but this one returns a pointer to NULL on a missing
  1852. X             * token.  Note the use of the field separator
  1853. X             * array.
  1854. X             */
  1855. X            for (i=0; i<3; i++) {
  1856. X                if (!(str = str_tok((char *) NULL, t_sep[i]))) {
  1857. X                    sprintf(message, "is missing a parameter at line %d", line);
  1858. X                    oops++;
  1859. X                    break;
  1860. X                }
  1861. X                switch (i) {
  1862. X                    case 0:
  1863. X                        m.tty[tty] = str_dup(str);
  1864. X                        break;
  1865. X                    case 1:
  1866. X                        m.tname[tty] = str_dup(str);
  1867. X                        break;
  1868. X                    case 2:
  1869. X                        m.lock_sp[tty] = atoi(str);
  1870. X                        break;
  1871. X                }
  1872. X            }
  1873. X            if (oops)
  1874. X                break;
  1875. X                    /* sanity checking */
  1876. X            sprintf(token, "TTY_%d", tty+1);
  1877. X            if (strcmp(token, temp_token)) {
  1878. X                sprintf(message, "is corrupted at line %d", line);
  1879. X                oops++;
  1880. X                break;
  1881. X            }
  1882. X            tty++;
  1883. X            continue;
  1884. X        }
  1885. X                    /* the modem database */
  1886. X        else {
  1887. X            sprintf(token, "MODEM_%d%c", mod+1, m_letter[m_line]);
  1888. X            if (strcmp(token, temp_token)) {
  1889. X                sprintf(message, "is corrupted at line %d", line);
  1890. X                oops++;
  1891. X                break;
  1892. X            }
  1893. X            /*
  1894. X             * There are three lines to the modem database.  They
  1895. X             * are distinguished by the letters a, b, and, c
  1896. X             * appended to the entry number.
  1897. X             */
  1898. X            switch (m_line) {
  1899. X                case 0:
  1900. X                    start = 0;
  1901. X                    stop = 5;
  1902. X                    break;
  1903. X                case 1:
  1904. X                    start = 5;
  1905. X                    stop = 13;
  1906. X                    break;
  1907. X                case 2:
  1908. X                    start = 13;
  1909. X                    stop = 17;
  1910. X                    break;
  1911. X            }
  1912. X            for (i=start; i<stop; i++) {
  1913. X                if (!(str = str_tok((char *) NULL, m_sep[i]))) {
  1914. X                    sprintf(message, "is missing a parameter at line %d", line);
  1915. X                    oops++;
  1916. X                    break;
  1917. X                }
  1918. X                switch (i) {
  1919. X                    case 0:
  1920. X                        m.mname[mod] = str_dup(str);
  1921. X                        break;
  1922. X                    case 1:
  1923. X                        m.init[mod] = str_dup(str);
  1924. X                        break;
  1925. X                    case 2:
  1926. X                        m.dial[mod] = str_dup(str);
  1927. X                        break;
  1928. X                    case 3:
  1929. X                        m.suffix[mod] = str_dup(str);
  1930. X                        break;
  1931. X                    case 4:
  1932. X                        m.hang_up[mod] = str_dup(str);
  1933. X                        break;
  1934. X                    case 5:
  1935. X                        m.auto_baud[mod] = *str;
  1936. X                        break;
  1937. X                    case 6:
  1938. X                        m.con_3[mod] = str_dup(str);
  1939. X                        break;
  1940. X                    case 7:
  1941. X                        m.con_12[mod] = str_dup(str);
  1942. X                        break;
  1943. X                    case 8:
  1944. X                        m.con_24[mod] = str_dup(str);
  1945. X                        break;
  1946. X                    case 9:
  1947. X                        m.con_48[mod] = str_dup(str);
  1948. X                        break;
  1949. X                    case 10:
  1950. X                        m.con_96[mod] = str_dup(str);
  1951. X                        break;
  1952. X                    case 11:
  1953. X                        m.con_192[mod] = str_dup(str);
  1954. X                        break;
  1955. X                    case 12:
  1956. X                        m.con_384[mod] = str_dup(str);
  1957. X                        break;
  1958. X                    case 13:
  1959. X                        m.no_con1[mod] = str_dup(str);
  1960. X                        break;
  1961. X                    case 14:
  1962. X                        m.no_con2[mod] = str_dup(str);
  1963. X                        break;
  1964. X                    case 15:
  1965. X                        m.no_con3[mod] = str_dup(str);
  1966. X                        break;
  1967. X                    case 16:
  1968. X                        m.no_con4[mod] = str_dup(str);
  1969. X                        break;
  1970. X                }
  1971. X            }
  1972. X            if (oops)
  1973. X                break;
  1974. X            m_line++;
  1975. X            if (m_line >= 3) {
  1976. X                m_line = 0;
  1977. X                mod++;
  1978. X            }
  1979. X        }
  1980. X    }
  1981. X    fclose(fp);
  1982. X
  1983. X    if (oops) {
  1984. X        sprintf(buf, "Modem/TTY database file \"%s\"", m.m_path);
  1985. X        error_win(1, buf, message);
  1986. X    }
  1987. X    m.t_entries = tty;
  1988. X    m.m_entries = mod;
  1989. X    m.t_cur = -1;
  1990. X    m.m_cur = -1;
  1991. X                    /* if empty database */
  1992. X    if (!tty) {
  1993. X        sprintf(buf, "Modem/TTY database file \"%s\"", m.m_path);
  1994. X        error_win(0, buf, "has no TTY data");
  1995. X    }
  1996. X    if (!mod) {
  1997. X        sprintf(buf, "Modem/TTY database file \"%s\"", m.m_path);
  1998. X        error_win(0, buf, "has no modem data");
  1999. X    }
  2000. X                    /* fill in the rest */
  2001. X    for (; tty<NUM_TTY; tty++) {
  2002. X        m.tty[tty] = null_ptr;
  2003. X        m.tname[tty] = null_ptr;
  2004. X        m.lock_sp[tty] = 0;
  2005. X    }
  2006. X    for (; mod<NUM_MODEM; mod++) {
  2007. X        m.mname[mod] = null_ptr;
  2008. X        m.init[mod] = null_ptr;
  2009. X        m.dial[mod] = null_ptr;
  2010. X        m.suffix[mod] = null_ptr;
  2011. X        m.hang_up[mod] = null_ptr;
  2012. X
  2013. X        m.auto_baud[mod] = 'Y';
  2014. X        m.con_3[mod] = null_ptr;
  2015. X        m.con_12[mod] = null_ptr;
  2016. X        m.con_24[mod] = null_ptr;
  2017. X        m.con_48[mod] = null_ptr;
  2018. X        m.con_96[mod] = null_ptr;
  2019. X        m.con_192[mod] = null_ptr;
  2020. X        m.con_384[mod] = null_ptr;
  2021. X
  2022. X        m.no_con1[mod] = null_ptr;
  2023. X        m.no_con2[mod] = null_ptr;
  2024. X        m.no_con3[mod] = null_ptr;
  2025. X        m.no_con4[mod] = null_ptr;
  2026. X    }
  2027. X    return(&m);
  2028. X}
  2029. X
  2030. X/*
  2031. X * Update the modem database.  Other routines actually do the changes
  2032. X * or deletions in memory.  A non-zero return code means non-fatal error.
  2033. X */
  2034. X
  2035. int
  2036. up_modem()
  2037. X{
  2038. X    FILE *fp, *uid_fopen();
  2039. X    char buf[80];
  2040. X    int i;
  2041. X    void error_win();
  2042. X
  2043. X                    /* open for write */
  2044. X    if (!(fp = uid_fopen(modem->m_path, "w"))) {
  2045. X        sprintf(buf, "\"%s\"", modem->m_path);
  2046. X        error_win(0, "No write permission on modem/TTY database file", buf);
  2047. X        return(1);
  2048. X    }
  2049. X                    /* put back the TTY entries */
  2050. X    for (i=0; i<modem->t_entries; i++)
  2051. X        fprintf(fp, "TTY_%d=%s;%s;%d\n", i+1, modem->tty[i],
  2052. X         modem->tname[i], modem->lock_sp[i]);
  2053. X
  2054. X                    /* put back the modem entries */
  2055. X    for (i=0; i<modem->m_entries; i++) {
  2056. X        fprintf(fp, "MODEM_%da=%s;%s;%s;%s;%s\n", i+1, modem->mname[i],
  2057. X         modem->init[i], modem->dial[i], modem->suffix[i],
  2058. X         modem->hang_up[i]);
  2059. X
  2060. X        fprintf(fp, "MODEM_%db=%c;%s;%s;%s;%s;%s;%s;%s\n", i+1,
  2061. X         modem->auto_baud[i], modem->con_3[i], modem->con_12[i],
  2062. X         modem->con_24[i], modem->con_48[i], modem->con_96[i],
  2063. X         modem->con_192[i], modem->con_384[i]);
  2064. X
  2065. X        fprintf(fp, "MODEM_%dc=%s;%s;%s;%s\n", i+1, modem->no_con1[i],
  2066. X         modem->no_con2[i], modem->no_con3[i], modem->no_con4[i]);
  2067. X    }
  2068. X
  2069. X    fclose(fp);
  2070. X    return(0);
  2071. X}
  2072. X
  2073. X/*
  2074. X * See if the new modem is already in the database.  If it's not, create
  2075. X * a slot for it and update the modem->m_cur variable.
  2076. X */
  2077. X
  2078. void
  2079. create_modem(str)
  2080. char *str;
  2081. X{
  2082. X    int i;
  2083. X    char *str_rep(), buf[80];
  2084. X    void error_win();
  2085. X                    /* modem entry already exists? */
  2086. X    for (i=0; i<modem->m_entries; i++) {
  2087. X        if (!strcmp(str, modem->mname[i]))
  2088. X            return;
  2089. X    }
  2090. X                    /* empty slot available? */
  2091. X    if (modem->m_entries == NUM_MODEM) {
  2092. X        sprintf(buf, "\"%s\"", modem->m_path);
  2093. X        error_win(0, "No empty modem slots in", buf);
  2094. X        return;
  2095. X    }
  2096. X                    /* create a new entry */
  2097. X    i = modem->m_entries;
  2098. X    modem->mname[i] = str_rep(modem->mname[i], str);
  2099. X
  2100. X                    /* update number of entries */
  2101. X    modem->m_entries++;
  2102. X    return;
  2103. X}
  2104. X
  2105. X/*
  2106. X * See if the modem names in the list still need to be in the database.
  2107. X * If you find a "lost" entry, delete it and collapse the list.
  2108. X */
  2109. X
  2110. void
  2111. del_modem()
  2112. X{
  2113. X    extern char *null_ptr;
  2114. X    int i, j, match;
  2115. X    char *str_rep();
  2116. X    void free_ptr();
  2117. X
  2118. X    for (i=0; i<modem->m_entries; i++) {
  2119. X        match = 0;
  2120. X        for (j=0; j<modem->t_entries; j++) {
  2121. X            if (!strcmp(modem->mname[i], modem->tname[j])) {
  2122. X                match++;
  2123. X                break;
  2124. X            }
  2125. X        }
  2126. X                    /* found a "lost" modem name */
  2127. X        if (!match) {
  2128. X            for (j=i; j<modem->m_entries-1; j++) {
  2129. X                    /* copy the info */
  2130. X                modem->mname[j] = str_rep(modem->mname[j], modem->mname[j+1]);
  2131. X                modem->init[j] = str_rep(modem->init[j], modem->init[j+1]);
  2132. X                modem->dial[j] = str_rep(modem->dial[j], modem->dial[j+1]);
  2133. X                modem->suffix[j] = str_rep(modem->suffix[j], modem->suffix[j+1]);
  2134. X                modem->hang_up[j] = str_rep(modem->hang_up[j], modem->hang_up[j+1]);
  2135. X
  2136. X                modem->auto_baud[j] = modem->auto_baud[j+1];
  2137. X                modem->con_3[j] = str_rep(modem->con_3[j], modem->con_3[j+1]);
  2138. X                modem->con_12[j] = str_rep(modem->con_12[j], modem->con_12[j+1]);
  2139. X                modem->con_24[j] = str_rep(modem->con_24[j], modem->con_24[j+1]);
  2140. X                modem->con_48[j] = str_rep(modem->con_48[j], modem->con_48[j+1]);
  2141. X                modem->con_96[j] = str_rep(modem->con_96[j], modem->con_96[j+1]);
  2142. X                modem->con_192[j] = str_rep(modem->con_192[j], modem->con_192[j+1]);
  2143. X                modem->con_384[j] = str_rep(modem->con_384[j], modem->con_384[j+1]);
  2144. X
  2145. X                modem->no_con1[j] = str_rep(modem->no_con1[j], modem->no_con1[j+1]);
  2146. X                modem->no_con2[j] = str_rep(modem->no_con2[j], modem->no_con2[j+1]);
  2147. X                modem->no_con3[j] = str_rep(modem->no_con3[j], modem->no_con3[j+1]);
  2148. X                modem->no_con4[j] = str_rep(modem->no_con4[j], modem->no_con4[j+1]);
  2149. X            }
  2150. X            j = modem->m_entries -1;
  2151. X
  2152. X            free_ptr(modem->mname[j]);
  2153. X            free_ptr(modem->init[j]);
  2154. X            free_ptr(modem->dial[j]);
  2155. X            free_ptr(modem->suffix[j]);
  2156. X            free_ptr(modem->hang_up[j]);
  2157. X
  2158. X            free_ptr(modem->con_3[j]);
  2159. X            free_ptr(modem->con_12[j]);
  2160. X            free_ptr(modem->con_24[j]);
  2161. X            free_ptr(modem->con_48[j]);
  2162. X            free_ptr(modem->con_96[j]);
  2163. X            free_ptr(modem->con_192[j]);
  2164. X            free_ptr(modem->con_384[j]);
  2165. X
  2166. X            free_ptr(modem->no_con1[j]);
  2167. X            free_ptr(modem->no_con2[j]);
  2168. X            free_ptr(modem->no_con3[j]);
  2169. X            free_ptr(modem->no_con4[j]);
  2170. X
  2171. X                    /* create an empty entry */
  2172. X            modem->mname[j] = null_ptr;
  2173. X            modem->init[j] = null_ptr;
  2174. X            modem->dial[j] = null_ptr;
  2175. X            modem->suffix[j] = null_ptr;
  2176. X            modem->hang_up[j] = null_ptr;
  2177. X
  2178. X            modem->auto_baud[j] = 'Y';
  2179. X            modem->con_3[j] = null_ptr;
  2180. X            modem->con_12[j] = null_ptr;
  2181. X            modem->con_24[j] = null_ptr;
  2182. X            modem->con_48[j] = null_ptr;
  2183. X            modem->con_96[j] = null_ptr;
  2184. X            modem->con_192[j] = null_ptr;
  2185. X            modem->con_384[j] = null_ptr;
  2186. X
  2187. X            modem->no_con1[j] = null_ptr;
  2188. X            modem->no_con2[j] = null_ptr;
  2189. X            modem->no_con3[j] = null_ptr;
  2190. X            modem->no_con4[j] = null_ptr;
  2191. X
  2192. X                    /* update the counts */
  2193. X            modem->m_entries--;
  2194. X            if (modem->m_cur >= modem->m_entries)
  2195. X                modem->m_cur = -1;
  2196. X            return;
  2197. X        }
  2198. X    }
  2199. X    return;
  2200. X}
  2201. END_OF_FILE
  2202. if test 10182 -ne `wc -c <'m_lib.c'`; then
  2203.     echo shar: \"'m_lib.c'\" unpacked with wrong size!
  2204. fi
  2205. # end of 'm_lib.c'
  2206. fi
  2207. if test -f 'main.c' -a "${1}" != "-c" ; then 
  2208.   echo shar: Will not clobber existing file \"'main.c'\"
  2209. else
  2210. echo shar: Extracting \"'main.c'\" \(10162 characters\)
  2211. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  2212. X/*
  2213. X * Pcomm is a public domain telecommunication program for Unix that
  2214. X * is designed to operate similarly to the MSDOS program, ProComm.
  2215. X * ProComm (TM) is copyrighted by Datastorm Technologies, Inc.
  2216. X *
  2217. X * Emmet P. Gray            US Army, HQ III Corps & Fort Hood
  2218. X * ...!uunet!uiucuxc!fthood!egray    Attn: AFZF-DE-ENV
  2219. X *                    Directorate of Engineering & Housing
  2220. X *                    Environmental Management Office
  2221. X *                    Fort Hood, TX 76544-5057
  2222. X *
  2223. X *    Release v1.0    12 Mar 88
  2224. X *    Release v1.1    21 Aug 88
  2225. X *    Release v1.2     4 Feb 89
  2226. X *    Release v2.0    18 Jul 92
  2227. X */
  2228. X
  2229. X#include <stdio.h>
  2230. X#include <ctype.h>
  2231. X#include <signal.h>
  2232. X#include <curses.h>
  2233. X#include <sys/types.h>
  2234. X#include <sys/stat.h>
  2235. X#define    MAIN
  2236. X#include "config.h"
  2237. X#include "dial_dir.h"
  2238. X#include "extrnl.h"
  2239. X#include "misc.h"
  2240. X#include "modem.h"
  2241. X#include "param.h"
  2242. X#include "status.h"
  2243. X
  2244. X#ifndef OLDCURSES
  2245. X#include <term.h>
  2246. X#else /* OLDCURSES */
  2247. X#ifdef UNIXPC
  2248. X#include <sgtty.h>
  2249. X#endif /* UNIXPC */
  2250. char tcbuf[1024];
  2251. struct sgttyb t_mode, c_mode;
  2252. X#ifndef cbreak
  2253. X#define cbreak crmode
  2254. X#endif
  2255. X#endif /* OLDCURSES */
  2256. X
  2257. struct DIAL_DIR *dir;
  2258. struct EXTRNL *extrnl;
  2259. struct MODEM *modem;
  2260. struct PARAM *param;
  2261. struct STATUS *status;
  2262. X
  2263. int fd = -1;                /* file descriptor for port */
  2264. int xmc;                /* magic cookie terminal */
  2265. int msg_status;                /* read/write permissions on TTY */
  2266. char *null_ptr = "";            /* generic char pointer to a null */
  2267. X
  2268. static int quit(), ci_match();
  2269. static void print_usage();
  2270. X
  2271. main(argc, argv)
  2272. int argc;
  2273. char *argv[];
  2274. X{
  2275. X    extern char *optarg;
  2276. X    int c, i, data_bits;
  2277. X    unsigned baud;
  2278. X    char *mytty, *ttyname(), *term, *getenv(), *sys_name, parity;
  2279. X    char *extra_dir, buf[80], message[80], *str_dup(), *number;
  2280. X    char *aux;
  2281. X    struct DIAL_DIR *read_dir();
  2282. X    struct EXTRNL *read_extrnl();
  2283. X    struct MODEM *read_modem();
  2284. X    struct PARAM *read_param();
  2285. X    struct STATUS *init();
  2286. X    struct stat stbuf;
  2287. X    void exit(), error_win(), vcs_table(), terminal(), free_ptr();
  2288. X    void info();
  2289. X#ifdef OLDCURSES
  2290. X    char *tgetstr(), *t, tb[1024];
  2291. X    t = tcbuf;
  2292. X#endif /* OLDCURSES */
  2293. X
  2294. X    signal(SIGINT, SIG_IGN);
  2295. X    signal(SIGQUIT, SIG_IGN);
  2296. X    signal(SIGTERM, (SIG_TYPE(*) ()) quit);
  2297. X    signal(SIGHUP, (SIG_TYPE(*) ()) quit);
  2298. X
  2299. X    extra_dir = NULL;
  2300. X    sys_name = NULL;
  2301. X    aux = NULL;
  2302. X    parity = '\0';
  2303. X    baud = 0;
  2304. X    data_bits = 0;
  2305. X    number = NULL;
  2306. X                    /* the command line */
  2307. X    while ((c = getopt(argc, argv, "d:f:a:eonw:b:p:")) != EOF) {
  2308. X        switch (c) {
  2309. X            case 'd':    /* the extra directory to search */
  2310. X                extra_dir = str_dup(optarg);
  2311. X                break;
  2312. X            case 'f':    /* the short cut into the dialing dir */
  2313. X                sys_name = str_dup(optarg);
  2314. X                break;
  2315. X            case 'a':    /* auxiliary (script, TTY, or modem) */
  2316. X                aux = str_dup(optarg);
  2317. X                break;
  2318. X            case 'e':
  2319. X                if (parity != '\0')
  2320. X                    print_usage("Parity values are mutually exclusive");
  2321. X                parity = 'E';
  2322. X                break;
  2323. X            case 'o':
  2324. X                if (parity != '\0')
  2325. X                    print_usage("Parity values are mutually exclusive");
  2326. X                parity = 'O';
  2327. X                break;
  2328. X            case 'n':
  2329. X                if (parity != '\0')
  2330. X                    print_usage("Parity values are mutually exclusive");
  2331. X                parity = 'N';
  2332. X                break;
  2333. X            case 'w':
  2334. X                data_bits = atoi(optarg);
  2335. X                if (data_bits != 7 && data_bits != 8)
  2336. X                    print_usage("Unsupported number of word length (data bits)");
  2337. X                break;
  2338. X            case 'b':
  2339. X                baud = (unsigned int) atoi(optarg);
  2340. X                switch (baud) {
  2341. X                    case 300:
  2342. X                    case 1200:
  2343. X                    case 2400:
  2344. X                    case 4800:
  2345. X                    case 9600:
  2346. X                    case 19200:
  2347. X                    case 38400:
  2348. X                        break;
  2349. X                    default:
  2350. X                        print_usage("Unsupported baud rate");
  2351. X                        break;
  2352. X                }
  2353. X                break;
  2354. X            case 'p':
  2355. X                number = str_dup(optarg);
  2356. X                break;
  2357. X            case '?':    /* default */
  2358. X                print_usage("");
  2359. X                break;
  2360. X        }
  2361. X    }
  2362. X                    /* get terminal type */
  2363. X    term = getenv("TERM");
  2364. X    if (term == NULL || *term == '\0') {
  2365. X        fprintf(stderr, "Windows not supported (TERM not defined)\n");
  2366. X        exit(1);
  2367. X    }
  2368. X                    /* see if terminfo entry exists */
  2369. X#ifdef OLDCURSES
  2370. X    i = tgetent(tb, term);
  2371. X#else /* OLDCURSES */
  2372. X    setupterm(term, 1, &i);
  2373. X#endif /* OLDCURSES */
  2374. X
  2375. X    if (i != 1) {
  2376. X        fprintf(stderr, "Windows not supported (no terminfo data for \"%s\")\n", term);
  2377. X        exit(1);
  2378. X    }
  2379. X                    /* minimum screen size */
  2380. X#ifdef OLDCURSES
  2381. X    if (tgetnum("co") < 80 || tgetnum("li") < 24) {
  2382. X#else /* OLDCURSES */
  2383. X    if (columns < 80 || lines < 24) {
  2384. X#endif /* OLDCURSES */
  2385. X        fprintf(stderr, "Windows not supported (minimum 80x24 screen required)\n");
  2386. X        exit(1);
  2387. X    }
  2388. X                    /* must have cursor movement */
  2389. X#ifdef OLDCURSES
  2390. X    if (tgetstr("cm", &t) == NULL) {
  2391. X#else /* OLDCURSES */
  2392. X    if (cursor_address == NULL) {
  2393. X#endif /* OLDCURSES */
  2394. X        fprintf(stderr, "Windows not supported (terminal too dumb)\n");
  2395. X        exit(1);
  2396. X    }
  2397. X                    /* load magic cookie variable */
  2398. X#ifdef OLDCURSES
  2399. X    xmc = tgetnum("sg");
  2400. X#else /* OLDCURSES */
  2401. X    xmc = magic_cookie_glitch;
  2402. X#endif /* OLDCURSES */
  2403. X                    /* ok... now let's go! */
  2404. X#ifdef OLDCURSES
  2405. X    ioctl(0, TIOCGETP, &t_mode);
  2406. X#endif /* OLDCURSES */
  2407. X
  2408. X    initscr();
  2409. X    nonl();
  2410. X    cbreak();
  2411. X    noecho();
  2412. X
  2413. X#ifdef OLDCURSES
  2414. X    ioctl(0, TIOCGETP, &c_mode);
  2415. X#endif /* OLDCURSES */
  2416. X
  2417. X    dir = (struct DIAL_DIR *) NULL;
  2418. X    extrnl = (struct EXTRNL *) NULL;
  2419. X    param = (struct PARAM *) NULL;
  2420. X    modem = (struct MODEM *) NULL;
  2421. X                    /* display herald if no arguments */
  2422. X    if (argc == 1) {
  2423. X        info(AUTO_CLEAR);
  2424. X        erase();
  2425. X        refresh();
  2426. X    }
  2427. X                    /* get "msgs" status */
  2428. X    if (mytty = ttyname(0)) {
  2429. X        stat(mytty, &stbuf);
  2430. X        msg_status = stbuf.st_mode & 0777;
  2431. X        chmod(mytty, 0600);
  2432. X    }
  2433. X
  2434. X    mvaddstr(12, 31, "Initializing...");
  2435. X    refresh();
  2436. X                    /* create the VCS table */
  2437. X    vcs_table();
  2438. X                    /* create the status structure */
  2439. X    status = init(extra_dir);
  2440. X                    /* read the support files */
  2441. X    param = read_param();
  2442. X    dir = read_dir();
  2443. X    extrnl = read_extrnl();
  2444. X    modem = read_modem();
  2445. X
  2446. X                    /* warning about screen size */
  2447. X    if (LINES > MAX_ROW || COLS > MAX_COL-1)
  2448. X        error_win(0, "Your screen size exceeds an internal Pcomm limit",
  2449. X         "The edges of the screen may contain garbage");
  2450. X
  2451. X                    /* short-cut to dialing window? */
  2452. X    if (sys_name != NULL) {
  2453. X        for (i=1; i<dir->d_entries+1; i++) {
  2454. X            if (ci_match(dir->name[i], sys_name)) {
  2455. X                dir->q_num[0] = i;
  2456. X                dir->d_cur = i;
  2457. X                if (!dial_win(25))
  2458. X                    aux = dir->aux[dir->d_cur];
  2459. X                break;
  2460. X            }
  2461. X        }
  2462. X                    /* if match not found */
  2463. X        if (dir->q_num[0] == -1) {
  2464. X            sprintf(buf, "Can't match \"%s\" in dialing directory", sys_name);
  2465. X            sprintf(message, "file \"%s\"", dir->d_path);
  2466. X            error_win(0, buf, message);
  2467. X        }
  2468. X        free_ptr(sys_name);
  2469. X    }
  2470. X                    /* phone number on the command line */
  2471. X    else if (number != NULL) {
  2472. X        dir->name[0] = str_dup(number);
  2473. X        dir->number[0] = str_dup(number);
  2474. X        if (baud)
  2475. X            dir->baud[0] = baud;
  2476. X        if (parity)
  2477. X            dir->parity[0] = parity;
  2478. X        if (data_bits)
  2479. X            dir->data_bits[0] = data_bits;
  2480. X        dir->q_num[0] = 0;
  2481. X        dir->d_cur = 0;
  2482. X
  2483. X        dial_win(25);
  2484. X        free_ptr(number);
  2485. X    }
  2486. X                    /* start terminal dialogue */
  2487. X    terminal(aux);
  2488. X    exit(0);
  2489. X}
  2490. X
  2491. X/*
  2492. X * Something dreadful happened...  Clean up the mess we made with the
  2493. X * TTY driver and release the phone line.
  2494. X */
  2495. X
  2496. static int
  2497. quit()
  2498. X{
  2499. X    void cleanup();
  2500. X
  2501. X    cleanup(1);
  2502. X                    /* never returns... */
  2503. X    return(0);
  2504. X}
  2505. X
  2506. X/*
  2507. X * Check write permission with the real UID and GID.  Returns a 0 on
  2508. X * permission denied, 1 on OK, and 2 on OK-but the file already exists.
  2509. X */
  2510. X
  2511. int
  2512. can_write(file)
  2513. char *file;
  2514. X{
  2515. X    char *p, path[256], *strcpy(), *strrchr();
  2516. X
  2517. X    strcpy(path, file);
  2518. X                    /* dissect the path component */
  2519. X    if (p = strrchr(path, '/'))
  2520. X        *p = '\0';
  2521. X    else
  2522. X        strcpy(path, ".");
  2523. X                    /* if it already exists */
  2524. X    if (!access(file, 0)) {
  2525. X        if (!access(file, 2))
  2526. X            return(OK_BUT_EXISTS);
  2527. X        return(DENIED);
  2528. X    }
  2529. X                    /* if path is writable */
  2530. X    if (!access(path, 2))
  2531. X        return(WRITE_OK);
  2532. X    return(DENIED);
  2533. X}
  2534. X
  2535. X/*
  2536. X * Check the read and write permissions before opening a file.  This
  2537. X * is a horrible kludge to work around the fact that a lot of systems
  2538. X * that claim to be SVID compatible don't treat setuid(2) and setgid(2)
  2539. X * properly.  For example, on a Masscomp, you can't flip-flop back and
  2540. X * forth between the real and effective UID/GID.
  2541. X */
  2542. X
  2543. XFILE *
  2544. uid_fopen(file, mode)
  2545. char *file, *mode;
  2546. X{
  2547. X    FILE *fp;
  2548. X
  2549. X#ifdef SETUID_BROKE
  2550. X    switch (*mode) {
  2551. X        case 'a':
  2552. X        case 'w':
  2553. X            switch(can_write(file)) {
  2554. X                case DENIED:
  2555. X                    fp = (FILE *) NULL;
  2556. X                    break;
  2557. X                case OK_BUT_EXISTS:
  2558. X                    fp = fopen(file, mode);
  2559. X                    break;
  2560. X                case WRITE_OK:
  2561. X                    fp = fopen(file, mode);
  2562. X                    chown(file, getuid(), getgid());
  2563. X                    break;
  2564. X            }
  2565. X            break;
  2566. X        case 'r':
  2567. X            if (access(file, 4))
  2568. X                fp = (FILE *) NULL;
  2569. X            else
  2570. X                fp = fopen(file, mode);
  2571. X            break;
  2572. X    }
  2573. X#else /* SETUID_BROKE */
  2574. X    int euid, egid;
  2575. X
  2576. X    euid = geteuid();
  2577. X    egid = getegid();
  2578. X                    /* abdicate the throne */
  2579. X    setuid(getuid());
  2580. X    setgid(getgid());
  2581. X
  2582. X    fp = fopen(file, mode);
  2583. X                    /* put things back */
  2584. X    setuid(euid);
  2585. X    setgid(egid);
  2586. X#endif /* SETUID_BROKE */
  2587. X    return(fp);
  2588. X}
  2589. X
  2590. X/*
  2591. X * See if s2 in contained in s1 (case insensitive).  Returns a 1 on yes,
  2592. X * and a 0 on no.
  2593. X */
  2594. X
  2595. static int
  2596. ci_match(s1, s2)
  2597. char *s1, *s2;
  2598. X{
  2599. X    int i;
  2600. X    char str1[128], str2[128], *strstr();
  2601. X
  2602. X                    /* copy the strings to lower case */
  2603. X    i = 0;
  2604. X    while(*s1) {
  2605. X        if (isupper(*s1))
  2606. X            str1[i++] = tolower(*s1);
  2607. X        else
  2608. X            str1[i++] = *s1;
  2609. X
  2610. X        if (i >= 127)
  2611. X            break;
  2612. X        s1++;
  2613. X    }
  2614. X    str1[i] = '\0';
  2615. X
  2616. X    i = 0;
  2617. X    while(*s2) {
  2618. X        if (isupper(*s2))
  2619. X            str2[i++] = tolower(*s2);
  2620. X        else
  2621. X            str2[i++] = *s2;
  2622. X
  2623. X        if (i >= 127)
  2624. X            break;
  2625. X        s2++;
  2626. X    }
  2627. X    str2[i] = '\0';
  2628. X                    /* do they match? */
  2629. X    if (strstr(str1, str2))
  2630. X        return(1);
  2631. X    return(0);
  2632. X}
  2633. X
  2634. static void
  2635. print_usage(err_message)
  2636. char *err_message;
  2637. X{
  2638. X    void exit();
  2639. X
  2640. X    if (*err_message != '\0')
  2641. X        fprintf(stderr, "Error: %s\n", err_message);
  2642. X    fprintf(stderr, "\nUsage: pcomm [-d directory] [-f system name] [-a auxiliary file]\n");
  2643. X    fprintf(stderr, "             [-e|o|n] [-w word length] [-b baud] [-p phone number]\n\n");
  2644. X    fprintf(stderr, "Command line options:\n");
  2645. X    fprintf(stderr, "\t-d use this directory to find Pcomm support files\n");
  2646. X    fprintf(stderr, "\t-f dial the entry that matches this system name\n");
  2647. X    fprintf(stderr, "\t-a auxiliary file (script, TTY, or modem)\n\n");
  2648. X    fprintf(stderr, "The following are used for manual dialing:\n");
  2649. X    fprintf(stderr, "\t-e use even parity\n");
  2650. X    fprintf(stderr, "\t-o use odd parity\n");
  2651. X    fprintf(stderr, "\t-n use no parity\n");
  2652. X    fprintf(stderr, "\t-w word length (number of data bits 7 or 8)\n");
  2653. X    fprintf(stderr, "\t-b baud rate (300, 1200, 2400, 4800, 9600, 19200, 38400)\n");
  2654. X    fprintf(stderr, "\t-p phone number to dial\n");
  2655. X    exit(1);
  2656. X}
  2657. END_OF_FILE
  2658. if test 10162 -ne `wc -c <'main.c'`; then
  2659.     echo shar: \"'main.c'\" unpacked with wrong size!
  2660. fi
  2661. # end of 'main.c'
  2662. fi
  2663. if test -f 'vcs.c' -a "${1}" != "-c" ; then 
  2664.   echo shar: Will not clobber existing file \"'vcs.c'\"
  2665. else
  2666. echo shar: Extracting \"'vcs.c'\" \(11086 characters\)
  2667. sed "s/^X//" >'vcs.c' <<'END_OF_FILE'
  2668. X/*
  2669. X * Routines for VCS detection.
  2670. X */
  2671. X
  2672. X#include <stdio.h>
  2673. X#include "config.h"
  2674. X#include "status.h"
  2675. X#include "vcs.h"
  2676. X
  2677. X#ifndef OLDCURSES
  2678. X#include <curses.h>
  2679. X#include <term.h>
  2680. X#endif /* OLDCURSES */
  2681. X
  2682. static int vcs_codes[NUM_VCS][VCS_SIZE];/* the VCS codes */
  2683. static int vcs_leadin[NUM_VCS];        /* unique list of lead-in characters */
  2684. static int num_leadin;            /* length of lead-in list */
  2685. static int putc_cnt;
  2686. static char putc_buf[VCS_SIZE];
  2687. static int substr(), fake_putc(), match_codes();
  2688. static void fake_it();
  2689. X
  2690. int vcs_param[NUM_VCS][5];        /* positional parameters */
  2691. int vcs_opt[NUM_VCS][10];        /* options unique to each VCS */
  2692. X
  2693. X/*
  2694. X * Test for possible VCS (video command sequence).  A character return
  2695. X * code means no match.  An return code greater than 255 means a VCS
  2696. X * was found.
  2697. X */
  2698. X
  2699. int
  2700. vcs_filter(c)
  2701. char c;
  2702. X{
  2703. X    static int vcs_buf[VCS_SIZE];
  2704. X    static int ptr = 0;
  2705. X    register int i;
  2706. X    int maybe, possible;
  2707. X
  2708. X                    /* see if possible */
  2709. X    possible = 0;
  2710. X    if (ptr == 0) {
  2711. X        /*
  2712. X         * This is kinda crude... I'm checking to see if the
  2713. X         * lead-in character is greater than the space character.
  2714. X         * If so, it most probably is NOT a VCS.
  2715. X         */
  2716. X        if (c >= ' ')
  2717. X            return(c & 0xff);
  2718. X                    /* check the list */
  2719. X        for (i=0; i<num_leadin; i++) {
  2720. X            if (c == vcs_leadin[i]) {
  2721. X                possible++;
  2722. X                break;
  2723. X            }
  2724. X        }
  2725. X        if (!possible)
  2726. X            return(c & 0xff);
  2727. X    }
  2728. X
  2729. X                    /* build the string */
  2730. X    vcs_buf[ptr++] = (unsigned char) c;
  2731. X    vcs_buf[ptr] = -1;
  2732. X                    /* test for match */
  2733. X    maybe = 0;
  2734. X    for (i=0; i<NUM_VCS; i++) {
  2735. X        switch (match_codes(vcs_buf, vcs_codes[i], i)) {
  2736. X            case YES:
  2737. X                ptr = 0;
  2738. X                return(i+256);
  2739. X            case NO:
  2740. X                break;
  2741. X            case MAYBE:
  2742. X                maybe++;
  2743. X                break;
  2744. X        }
  2745. X    }
  2746. X                    /* abandon what you've got */
  2747. X    if (maybe && ptr == VCS_SIZE-1) {
  2748. X        ptr = 0;
  2749. X        return(c & 0xff);
  2750. X    }
  2751. X                    /* hang on, wait and see */
  2752. X    if (maybe)
  2753. X        return(MAYBE);
  2754. X                    /* a clean miss */
  2755. X    ptr = 0;
  2756. X    return(c & 0xff);
  2757. X}
  2758. X
  2759. X/*
  2760. X * See if the two integer arrays "match".  Character parameters are
  2761. X * designated by codes > 1000 and ASCII digit parameters are designated
  2762. X * by codes > 2000.  Uses a simple linear search, so if NUM_VCS grows
  2763. X * this routine will have to mature a bit.
  2764. X */
  2765. X
  2766. static int
  2767. match_codes(test, code, k)
  2768. int test[], code[], k;
  2769. X{
  2770. X    extern int vcs_param[NUM_VCS][5];
  2771. X    register int i, j;
  2772. X    int pos, done;
  2773. X                    /* doesn't exist */
  2774. X    if (code[0] == -1)
  2775. X        return(NO);
  2776. X
  2777. X    i = 0;
  2778. X    j = 0;
  2779. X    while (i<VCS_SIZE && j<VCS_SIZE) {
  2780. X                    /* at the end (a match) */
  2781. X        if (test[i] == -1 && code[j] == -1)
  2782. X            return(YES);
  2783. X                    /* ran out of input */
  2784. X        if (test[i] == -1)
  2785. X            break;
  2786. X        /*
  2787. X         * The char parameter (code 1000) always matches the
  2788. X         * next character.
  2789. X         */
  2790. X        if (code[j] >= 1000 && code[j] < 2000) {
  2791. X            pos = code[j] -1000;
  2792. X            vcs_param[k][pos] = test[i];
  2793. X            i++;
  2794. X            j++;
  2795. X            continue;
  2796. X        }
  2797. X        /*
  2798. X         * The digit parameter (code 2000) tries to match as many
  2799. X         * ASCII digits as it can.
  2800. X         */
  2801. X        if (code[j] >= 2000) {
  2802. X            pos = code[j] -2000;
  2803. X                    /* done with this number? */
  2804. X            if (vcs_param[k][pos])
  2805. X                done = 1;
  2806. X            else
  2807. X                done = 0;
  2808. X                    /* only digits */
  2809. X            while (test[i] >= 48 && test[i] <= 57) {
  2810. X                if (!done)
  2811. X                    vcs_param[k][pos] = (vcs_param[k][pos] * 10) + test[i] -48;
  2812. X                i++;
  2813. X            }
  2814. X                    /* ended in a digit */
  2815. X            if (test[i] == -1 && code[j+1] != -1) {
  2816. X                vcs_param[k][pos] = 0;
  2817. X                break;
  2818. X            }
  2819. X            j++;
  2820. X            continue;
  2821. X        }
  2822. X                    /* a clean miss */
  2823. X        if (test[i] != code[j]) {
  2824. X            for (j=0; j<5; j++)
  2825. X                vcs_param[k][j] = 0;
  2826. X            return(NO);
  2827. X        }
  2828. X        i++;
  2829. X        j++;
  2830. X    }
  2831. X                    /* a maybe */
  2832. X    return(MAYBE);
  2833. X}
  2834. X
  2835. X/*
  2836. X * Build the table of VCS codes.  Actually we cheat... We tell curses(3)
  2837. X * to build the strings to perform the function, and then we decipher
  2838. X * what it did.
  2839. X *
  2840. X * For example: On a vt100 the cursor motion string in terminfo is:
  2841. X *    cup=\E[%i%p1%d;%p2%dH$<5>
  2842. X *
  2843. X * This gets translated to the integer array vcs_code[] as:
  2844. X *    \E   [   %p1%d  ;   %p2%d  H
  2845. X *    27,  91, 2000,  59, 2001,  72
  2846. X * 
  2847. X * Notice that the "%p1" and "%p2" parameters get translated to 2000 and
  2848. X * 2001.  This is to signify that the parameters are multiple digit ASCII
  2849. X * encoded numbers.  The "%i" and "%d" codes are embedded into the vcs_opt[]
  2850. X * array in somewhat of a loose manner.  In other words, there is no set
  2851. X * format for the vcs_opt[] array.  The padding info "$<5>" is ignored.
  2852. X */
  2853. X
  2854. void
  2855. vcs_table()
  2856. X{
  2857. X    int i, j, k, match, temp[VCS_SIZE];
  2858. X    char *p, *strcpy(), buf[VCS_SIZE];
  2859. X    char *tparm();            /* <- comment out, if required */
  2860. X
  2861. X#ifdef OLDCURSES
  2862. X    extern char tcbuf[1024];
  2863. X    char *t, *cursor_home, *clr_eol, *clr_eos;
  2864. X    char *clear_screen, *cursor_up, *cursor_down, *cursor_right;
  2865. X    char *cursor_left, *cursor_address, *tgetstr(), *tgoto();
  2866. X
  2867. X    t = tcbuf;
  2868. X    cursor_home = tgetstr("ho", &t);
  2869. X    clr_eol = tgetstr("ce", &t);
  2870. X    clr_eos = tgetstr("cd", &t);
  2871. X    clear_screen = tgetstr("cl", &t);
  2872. X    cursor_up = tgetstr("up", &t);
  2873. X    cursor_down = tgetstr("do", &t);
  2874. X    cursor_right = tgetstr("nd", &t);
  2875. X    cursor_left = tgetstr("le", &t);
  2876. X    cursor_address = tgetstr("cm", &t);
  2877. X#endif /* OLDCURSES */
  2878. X
  2879. X    /*
  2880. X     * Do the easy ones first.  These don't take positional parameters,
  2881. X     * so all we have to do is strip the padding info.
  2882. X     */
  2883. X    for (i=0; i<NUM_VCS; i++) {
  2884. X        switch (i) {
  2885. X            case HOME:
  2886. X                p = cursor_home;
  2887. X                break;
  2888. X            case CLR_EOL:
  2889. X                p = clr_eol;
  2890. X                break;
  2891. X            case CLR_EOS:
  2892. X                p = clr_eos;
  2893. X                break;
  2894. X            case CLEAR:
  2895. X                p = clear_screen;
  2896. X                break;
  2897. X            case MV_UP:
  2898. X                p = cursor_up;
  2899. X                break;
  2900. X            case MV_DOWN:
  2901. X                p = cursor_down;
  2902. X                break;
  2903. X            case MV_RIGHT:
  2904. X                p = cursor_right;
  2905. X                break;
  2906. X            case MV_LEFT:
  2907. X                p = cursor_left;
  2908. X                break;
  2909. X            default:
  2910. X                p = "";
  2911. X                break;
  2912. X        }
  2913. X        /*
  2914. X         * Either the capability doesn't exist, or we're gonna
  2915. X         * do this one by hand (i.e.: ones with positional parameters)
  2916. X         */
  2917. X        if (!p) {
  2918. X            vcs_codes[i][0] = -1;
  2919. X            continue;
  2920. X        }
  2921. X                    /* fake an "output" */
  2922. X        fake_it(p);
  2923. X                    /* copy what it did */
  2924. X        j = 0;
  2925. X        while (putc_buf[j]) {
  2926. X            vcs_codes[i][j] = (unsigned char) putc_buf[j];
  2927. X            j++;
  2928. X            if (j == VCS_SIZE-1)
  2929. X                break;
  2930. X        }
  2931. X        vcs_codes[i][j] = -1;
  2932. X    }
  2933. X
  2934. X    /*
  2935. X     * And now for the difficult ones.  The way it's done is: load the
  2936. X     * string with a few known parameters and then find where the
  2937. X     * parameters end up.  The vcs_opt[][] array is "free-flowing"
  2938. X     * and means something only to the routine being used.
  2939. X     */
  2940. X                    /* add one to the param */
  2941. X    if (substr(cursor_address, "%i") > 0) {
  2942. X        vcs_opt[MV_DIRECT][0] = 1;
  2943. X        vcs_opt[MV_DIRECT][1] = 1;
  2944. X    }
  2945. X                    /* decimal codes used */
  2946. X    if (substr(cursor_address, "%d") > 0)
  2947. X        vcs_opt[MV_DIRECT][1] = 1;
  2948. X                    /* character codes used */
  2949. X    if (substr(cursor_address, "%c") > 0)
  2950. X        vcs_opt[MV_DIRECT][2] = 1;
  2951. X                    /* add an offset */
  2952. X    if (substr(cursor_address, "%+") > 0)
  2953. X        vcs_opt[MV_DIRECT][3] = 1;
  2954. X                    /* subtract an offset */
  2955. X    if (substr(cursor_address, "%-") > 0)
  2956. X        vcs_opt[MV_DIRECT][4] = 1;
  2957. X                    /* load with parameters 12 & 34 */
  2958. X#ifdef OLDCURSES
  2959. X    fake_it(tgoto(cursor_address, 12, 34));
  2960. X#else /* OLDCURSES */
  2961. X    fake_it((char *)tparm(cursor_address, 12, 34));
  2962. X#endif /* OLDCURSES */
  2963. X
  2964. X    j = 0;
  2965. X    while (putc_buf[j]) {
  2966. X        temp[j] = (unsigned char) putc_buf[j];
  2967. X        j++;
  2968. X        if (j == VCS_SIZE-1)
  2969. X            break;
  2970. X    }
  2971. X    temp[j] = -1;
  2972. X                    /* if decimal parameters */
  2973. X    if (vcs_opt[MV_DIRECT][1]) {
  2974. X                    /* if add one */
  2975. X        if (vcs_opt[MV_DIRECT][0])
  2976. X            strcpy(buf, "13");
  2977. X        else
  2978. X            strcpy(buf, "12");
  2979. X                    /* where is the 12 (or 13)? */
  2980. X        if ((i = substr(putc_buf, buf)) > 0) {
  2981. X            temp[i] = 2000;
  2982. X            temp[i+1] = -2;
  2983. X        }
  2984. X        else
  2985. X            temp[0] = -1;
  2986. X                    /* if add one */
  2987. X        if (vcs_opt[MV_DIRECT][0])
  2988. X            strcpy(buf, "35");
  2989. X        else
  2990. X            strcpy(buf, "34");
  2991. X                    /* where is the 34 (or 35)? */
  2992. X        if ((i = substr(putc_buf, buf)) > 0) {
  2993. X            temp[i] = 2001;
  2994. X            temp[i+1] = -2;
  2995. X        }
  2996. X        else
  2997. X            temp[0] = -1;
  2998. X    }
  2999. X                    /* if character parameters */
  3000. X    if (vcs_opt[MV_DIRECT][2]) {
  3001. X                    /* original with 12 and 34 */
  3002. X        strcpy(buf, putc_buf);
  3003. X                    /* change 12 to 13 */
  3004. X#ifdef OLDCURSES
  3005. X        fake_it(tgoto(cursor_address, 13, 34));
  3006. X#else /* OLDCURSES */
  3007. X        fake_it((char *)tparm(cursor_address, 13, 34));
  3008. X#endif /* OLDCURSES */
  3009. X                    /* where are they different */
  3010. X        i = 0;
  3011. X        while (buf[i] != '\0') {
  3012. X            if (buf[i] != putc_buf[i])
  3013. X                break;
  3014. X            i++;
  3015. X        }
  3016. X                    /* sanity checking */
  3017. X        if (buf[i] == '\0')
  3018. X            temp[0] = -1;
  3019. X                    /* if add, what is offset? */
  3020. X        if (vcs_opt[MV_DIRECT][3])
  3021. X            vcs_opt[MV_DIRECT][5] = temp[i] - 13;
  3022. X
  3023. X                    /* if subtract, what is offset? */
  3024. X        if (vcs_opt[MV_DIRECT][4])
  3025. X            vcs_opt[MV_DIRECT][5] = 13 - temp[i];
  3026. X
  3027. X        temp[i] = 1000;
  3028. X                    /* change 34 to 35 */
  3029. X#ifdef OLDCURSES
  3030. X        fake_it(tgoto(cursor_address, 12, 35));
  3031. X#else /* OLDCURSES */
  3032. X        fake_it((char *)tparm(cursor_address, 12, 35));
  3033. X#endif /* OLDCURSES */
  3034. X                    /* where are they different */
  3035. X        i = 0;
  3036. X        while (buf[i] != '\0') {
  3037. X            if (buf[i] != putc_buf[i])
  3038. X                break;
  3039. X            i++;
  3040. X        }
  3041. X        temp[i] = 1001;
  3042. X        if (buf[i] == '\0')
  3043. X            temp[0] = -1;
  3044. X    }
  3045. X                    /* strip the -2's out, if any */
  3046. X    i = 0;
  3047. X    j = 0;
  3048. X    while (temp[i] != -1) {
  3049. X        if (temp[i] != -2)
  3050. X            vcs_codes[MV_DIRECT][j++] = temp[i];
  3051. X        i++;
  3052. X    }
  3053. X    vcs_codes[MV_DIRECT][j] = -1;
  3054. X
  3055. X    /*
  3056. X     * Simplify the list.  Some codes are already handled by the
  3057. X     * virtual screen routines... no need to duplicate them.
  3058. X     */
  3059. X    if (vcs_codes[MV_DOWN][0] == '\n')
  3060. X        vcs_codes[MV_DOWN][0] = -1;
  3061. X
  3062. X    if (vcs_codes[MV_LEFT][0] == 8)
  3063. X        vcs_codes[MV_LEFT][0] = -1;
  3064. X
  3065. X    /*
  3066. X     * Often the "clear screen" sequence will contain the "home"
  3067. X     * sequence... if so, don't duplicate the "home" portion.
  3068. X     */
  3069. X    fake_it(cursor_home);
  3070. X    strcpy(buf, putc_buf);
  3071. X
  3072. X    fake_it(clear_screen);
  3073. X                    /* if "home" inside "clear screen" */
  3074. X    if ((k = substr(putc_buf, buf)) >= 0) {
  3075. X                    /* if at the beginning */
  3076. X        if (k == 0) {
  3077. X            i = 0;
  3078. X            for (j=strlen(buf); j<VCS_SIZE; j++)
  3079. X                vcs_codes[CLEAR][i++] = (unsigned char) putc_buf[j];
  3080. X            vcs_codes[CLEAR][i] = -1;
  3081. X        }
  3082. X                    /* if at the end */
  3083. X        else if (strlen(buf)+k == strlen(putc_buf))
  3084. X            vcs_codes[CLEAR][k] = -1;
  3085. X    }
  3086. X                    /* is "clear screen" still unique */
  3087. X    k = 0;
  3088. X    for (i=0; i<NUM_VCS; i++) {
  3089. X        if (vcs_codes[CLEAR][i] == -1 || vcs_codes[CLR_EOS][i] == -1)
  3090. X            break;
  3091. X        if (vcs_codes[CLEAR][i] != vcs_codes[CLR_EOS][i]) {
  3092. X            k++;
  3093. X            break;
  3094. X        }
  3095. X    }
  3096. X    if (k == 0)
  3097. X        vcs_codes[CLEAR][0] = -1;
  3098. X
  3099. X    /*
  3100. X     * Make a list of unique lead-in characters to be used as a
  3101. X     * simple hash table.
  3102. X     */
  3103. X    num_leadin = 0;
  3104. X    for (i=0; i<NUM_VCS; i++) {
  3105. X        if (vcs_codes[i][0] == -1)
  3106. X            continue;
  3107. X                    /* add any new lead-in character */
  3108. X        match = 0;
  3109. X        for (j=0; j<num_leadin; j++) {
  3110. X            if (vcs_leadin[j] == vcs_codes[i][0])
  3111. X                match++;
  3112. X        }
  3113. X        if (!match)
  3114. X            vcs_leadin[num_leadin++] = vcs_codes[i][0];
  3115. X    }
  3116. X    return;
  3117. X}
  3118. X
  3119. X/*
  3120. X * The routine that fakes curses(3) into outputting the string info with
  3121. X * the padding removed.
  3122. X */
  3123. X
  3124. static void
  3125. fake_it(s)
  3126. char *s;
  3127. X{
  3128. X    putc_cnt = 0;
  3129. X    putc_buf[0] = '\0';
  3130. X    tputs(s, 1, fake_putc);
  3131. X    putc_buf[putc_cnt] = '\0';
  3132. X    return;
  3133. X}
  3134. X
  3135. static int
  3136. fake_putc(c)
  3137. char c;
  3138. X{
  3139. X    if (c != '\0')
  3140. X        putc_buf[putc_cnt++] = (unsigned char) c;
  3141. X    return((unsigned char) c);
  3142. X}
  3143. X
  3144. X/*
  3145. X * Is string2 contained in string1?  If so, return the offset, otherwise
  3146. X * return a -1.
  3147. X */
  3148. X
  3149. static int
  3150. substr(s1, s2)
  3151. char *s1, *s2;
  3152. X{
  3153. X    int i, len;
  3154. X
  3155. X    len = strlen(s2);
  3156. X                    /* not possible */
  3157. X    if (len > strlen(s1))
  3158. X        return(-1);
  3159. X
  3160. X    i = 0;
  3161. X    while (*s1) {
  3162. X        if (!strncmp(s1, s2, len))
  3163. X            return(i);
  3164. X        s1++;
  3165. X        i++;
  3166. X    }
  3167. X    return(-1);
  3168. X}
  3169. END_OF_FILE
  3170. if test 11086 -ne `wc -c <'vcs.c'`; then
  3171.     echo shar: \"'vcs.c'\" unpacked with wrong size!
  3172. fi
  3173. # end of 'vcs.c'
  3174. fi
  3175. if test -f 'x_rcv.c' -a "${1}" != "-c" ; then 
  3176.   echo shar: Will not clobber existing file \"'x_rcv.c'\"
  3177. else
  3178. echo shar: Extracting \"'x_rcv.c'\" \(12062 characters\)
  3179. sed "s/^X//" >'x_rcv.c' <<'END_OF_FILE'
  3180. X/*
  3181. X * Receive a list of files using a version of Ward Christensen's file
  3182. X * transfer protocol.  A non-zero return code means the user must acknowledge
  3183. X * an error condition (a user generated abort returns a 0).  Write errors
  3184. X * are considered fatal.
  3185. X */
  3186. X
  3187. X#include <stdio.h>
  3188. X#include <curses.h>
  3189. X#include "config.h"
  3190. X#include "dial_dir.h"
  3191. X#include "misc.h"
  3192. X#include "xmodem.h"
  3193. X
  3194. unsigned char buf[1029];
  3195. char file_name[15];
  3196. long file_length;
  3197. X
  3198. static int err_method, tot_err, block_size;
  3199. static int send_first();
  3200. X
  3201. int
  3202. rcv_xmodem(win, list, type)
  3203. WINDOW *win;
  3204. char *list;
  3205. int type;
  3206. X{
  3207. X    extern char *protocol[];
  3208. X    FILE *fp, *uid_fopen();
  3209. X    int i, default_err, is_batch, max_block, code, file_count, got_hdr;
  3210. X    int hours, mins, secs, len;
  3211. X    long block, recv, partial;
  3212. X    float percent, performance;
  3213. X    unsigned char blk;
  3214. X    unsigned int sleep();
  3215. X    char *file, *name, *strcpy(), *strrchr(), *strtok();
  3216. X    void cancel_xfer();
  3217. X                    /* which protocol? */
  3218. X    switch (type) {
  3219. X        case XMODEM:
  3220. X            default_err = CRC_CHECKSUM;
  3221. X            is_batch = 0;
  3222. X            max_block = 128;
  3223. X            break;
  3224. X        case XMODEM_1k:
  3225. X            default_err = CRC_CHECKSUM;
  3226. X            is_batch = 0;
  3227. X            max_block = 1024;
  3228. X            break;
  3229. X        case MODEM7:
  3230. X            default_err = CHECKSUM;
  3231. X            is_batch = 1;
  3232. X            max_block = 128;
  3233. X            break;
  3234. X        case YMODEM:
  3235. X            default_err = CRC;
  3236. X            is_batch = 1;
  3237. X            max_block = 1024;
  3238. X            performance = 1.09;
  3239. X            break;
  3240. X        case YMODEM_G:
  3241. X            default_err = NONE;
  3242. X            is_batch = 1;
  3243. X            max_block = 1024;
  3244. X            performance = 1.02;
  3245. X            break;
  3246. X        default:
  3247. X            return(1);
  3248. X    }
  3249. X
  3250. X    tot_err = 0;
  3251. X    file_count = 0;
  3252. X    mvwaddstr(win, 2, 24, protocol[type -1]);
  3253. X    mvwaddstr(win, 11, 24, "0  ");
  3254. X
  3255. X    /* CONSTCOND */
  3256. X    while (1) {
  3257. X        file_count++;
  3258. X        file_length = 0L;
  3259. X                    /* user supplied name */
  3260. X        if (!is_batch) {
  3261. X            if (file_count > 1)
  3262. X                break;
  3263. X
  3264. X            file = strtok(list, " \t");
  3265. X                    /* dissect the file name */
  3266. X            if ((name = strrchr(file, '/')))
  3267. X                strcpy(file_name, ++name);
  3268. X            else
  3269. X                strcpy(file_name, file);
  3270. X        }
  3271. X                    /* get the modem7 file name */
  3272. X        if (type == MODEM7) {
  3273. X            if (code = rcv_modem7(win, default_err))
  3274. X                return(code +1);
  3275. X
  3276. X            file = file_name;
  3277. X        }
  3278. X                    /* get the block 0 */
  3279. X        if (type == YMODEM || type == YMODEM_G) {
  3280. X            if (code = send_first(win, max_block, default_err))
  3281. X                return(code +1);
  3282. X
  3283. X            if (code = rcv_ymodem(win))
  3284. X                return(code +1);
  3285. X
  3286. X                    /* at the end? */
  3287. X            if (buf[3] == '\0') {
  3288. X                beep();
  3289. X                wrefresh(win);
  3290. X                putc_line(ACK);
  3291. X                sleep(1);
  3292. X                return(0);
  3293. X            }
  3294. X            file = file_name;
  3295. X        }
  3296. X                    /* any trouble? */
  3297. X        if (file_name[0] == '\0')
  3298. X            continue;
  3299. X
  3300. X        clear_line(win, 3, 24, TRUE);
  3301. X        waddstr(win, file_name);
  3302. X                    /* if file length is known */
  3303. X        if (file_length != 0L) {
  3304. X            mvwprintw(win, 4, 24, "%-10ld", file_length);
  3305. X
  3306. X            secs = (file_length * 10.0 / dir->baud[0]) * performance;
  3307. X            hours = secs / 3600;
  3308. X            mins = (secs % 3600) / 60;
  3309. X            secs = (secs % 3600) % 60;
  3310. X
  3311. X            mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
  3312. X        }
  3313. X                    /* some starting numbers */
  3314. X        mvwaddstr(win, 7, 24, "0    ");
  3315. X        if (file_length != 0L)
  3316. X            mvwaddstr(win, 8, 24, "0%  ");
  3317. X        mvwaddstr(win, 9, 24, "0          ");
  3318. X        mvwaddstr(win, 10, 24, "0 ");
  3319. X        clear_line(win, 12, 24, TRUE);
  3320. X        waddstr(win, "NONE");
  3321. X        wrefresh(win);
  3322. X
  3323. X        /*
  3324. X         * If the user supplied the name, write permission is checked
  3325. X         * by the get_names() routine in xfer_menu().  If modem7
  3326. X         * or ymodem supplied name, the name is unique and the write
  3327. X         * permission on the directory is checked by the change_name()
  3328. X         * routines.  However, this is required for systems with
  3329. X         * SETUID_BROKE set.
  3330. X         */
  3331. X                    /* open the file */
  3332. X        if (!(fp = uid_fopen(file, "w"))) {
  3333. X            beep();
  3334. X            clear_line(win, 12, 24, TRUE);
  3335. X            wattrstr(win, A_BOLD, "CAN'T OPEN FILE");
  3336. X            wrefresh(win);
  3337. X            cancel_xfer(DOWN_LOAD);
  3338. X            return(1);
  3339. X        }
  3340. X                    /* ACK the block 0 */
  3341. X        if (type == YMODEM || type == YMODEM_G)
  3342. X            putc_line(ACK);
  3343. X
  3344. X        if (code = send_first(win, max_block, default_err)) {
  3345. X            fclose(fp);
  3346. X            return(code +1);
  3347. X        }
  3348. X                    /* here we go... */
  3349. X        clear_line(win, 12, 24, TRUE);
  3350. X        waddstr(win, "NONE");
  3351. X        wrefresh(win);
  3352. X        blk = 1;
  3353. X        block = 1L;
  3354. X        recv = 0L;
  3355. X        got_hdr = 1;
  3356. X        /* CONSTCOND */
  3357. X        while (1) {
  3358. X            code = rcv_block(win, got_hdr, max_block, blk);
  3359. X
  3360. X            if (code < 0) {
  3361. X                fclose(fp);
  3362. X                return(code +1);
  3363. X            }
  3364. X            got_hdr = 0;
  3365. X                    /* are we done? */
  3366. X            if (buf[0] == EOT) {
  3367. X                if (!is_batch) {
  3368. X                    beep();
  3369. X                    wrefresh(win);
  3370. X                    sleep(1);
  3371. X                }
  3372. X                break;
  3373. X            }
  3374. X                    /* if not a duplicate block */
  3375. X            if (!code) {
  3376. X                if (file_length != 0L) {
  3377. X                    partial = file_length - recv;
  3378. X                    if (partial > (long) block_size)
  3379. X                        len = block_size;
  3380. X                    else
  3381. X                        len = (int) partial;
  3382. X                }
  3383. X                else
  3384. X                    len = block_size;
  3385. X
  3386. X                if (fwrite((char *) &buf[3], sizeof(char), len, fp) != len) {
  3387. X                    beep();
  3388. X                    clear_line(win, 12, 24, TRUE);
  3389. X                    wattrstr(win, A_BOLD, "WRITE ERROR");
  3390. X                    wrefresh(win);
  3391. X                    cancel_xfer(DOWN_LOAD);
  3392. X                    fclose(fp);
  3393. X                    /* fatal */
  3394. X                    return(1);
  3395. X                }
  3396. X                mvwprintw(win, 7, 24, "%-5ld", block);
  3397. X                recv = recv + (unsigned int) len;
  3398. X                mvwprintw(win, 9, 24, "%-10ld", recv);
  3399. X                blk++;
  3400. X                block++;
  3401. X            }
  3402. X            /*
  3403. X             * If the length is known, give the same status
  3404. X             * report as uploading
  3405. X             */
  3406. X            if (file_length != 0L) {
  3407. X                percent = recv * 100.0 / file_length;
  3408. X                if (percent > 100.0)
  3409. X                    percent = 100.0;
  3410. X                mvwprintw(win, 8, 24, "%0.1f%%", percent);
  3411. X            }
  3412. X            wrefresh(win);
  3413. X            putc_line(ACK);
  3414. X        }
  3415. X        if (file_length != 0L) {
  3416. X            mvwaddstr(win, 8, 24, "100%  ");
  3417. X            wrefresh(win);
  3418. X        }
  3419. X        /*
  3420. X         * If the file length is not known, search backwards from
  3421. X         * the end of the file until you find a character that is
  3422. X         * not the ^Z padding character.
  3423. X         */
  3424. X        if (file_length == 0L) {
  3425. X            for (i=block_size+2; i>2; i--) {
  3426. X                if (buf[i] != CTRLZ)
  3427. X                    break;
  3428. X            }
  3429. X            file_length = recv - (unsigned int) block_size + (unsigned int) i -2L;
  3430. X            fclose(fp);
  3431. X            if (fix_length(file, file_length)) {
  3432. X                beep();
  3433. X                clear_line(win, 12, 24, TRUE);
  3434. X                wattrstr(win, A_BOLD, "TRUNCATE ERROR");
  3435. X                wrefresh(win);
  3436. X                sleep(1);
  3437. X            }
  3438. X        }
  3439. X        else
  3440. X            fclose(fp);
  3441. X                    /* ACK the EOT */
  3442. X        putc_line(ACK);
  3443. X    }
  3444. X    return(0);
  3445. X}
  3446. X
  3447. X/*
  3448. X * Send the first character to start the transmission and set the error
  3449. X * checking method.  Returns the standard error codes or 0 on success.
  3450. X * The variables err_method and block_size are global.
  3451. X */
  3452. X
  3453. static int
  3454. send_first(win, max_block, default_err)
  3455. WINDOW *win;
  3456. int max_block, default_err;
  3457. X{
  3458. X    int i, err_count;
  3459. X    unsigned int sleep();
  3460. X    void cancel_xfer();
  3461. X                    /* default error method */
  3462. X    err_method = default_err;
  3463. X    if (default_err == CRC_CHECKSUM)
  3464. X        err_method = CRC;
  3465. X                    /* send the first char */
  3466. X    err_count = 0;
  3467. X    while (err_count < MAX_ERRORS*2) {
  3468. X        mvwprintw(win, 10, 24, "%-2d", err_count);
  3469. X
  3470. X                    /* scan the keyboard for abort */
  3471. X        if (wgetch(win) == ESC) {
  3472. X            beep();
  3473. X            clear_line(win, 12, 24, TRUE);
  3474. X            waddstr(win, "ABORTED");
  3475. X            wrefresh(win);
  3476. X            cancel_xfer(DOWN_LOAD);
  3477. X            sleep(3);
  3478. X            return(ABORT);
  3479. X        }
  3480. X                    /* switch to checksum? */
  3481. X        if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
  3482. X            err_method = CHECKSUM;
  3483. X
  3484. X                    /* send error method code */
  3485. X        clear_line(win, 5, 24, TRUE);
  3486. X        switch (err_method) {
  3487. X            case CHECKSUM:
  3488. X                waddstr(win, "CHECKSUM");
  3489. X                putc_line(NAK);
  3490. X                break;
  3491. X            case CRC:
  3492. X                waddstr(win, "CRC");
  3493. X                putc_line('C');
  3494. X                break;
  3495. X            case NONE:
  3496. X                waddstr(win, "NONE");
  3497. X                putc_line('G');
  3498. X                break;
  3499. X        }
  3500. X        /*
  3501. X         * We've cut the delay time in half, so we double
  3502. X         * the allowable errors
  3503. X         */
  3504. X        if ((i = getc_line(5)) == -1) {
  3505. X            err_count++;
  3506. X            clear_line(win, 12, 24, TRUE);
  3507. X            waddstr(win, "NO RESPONSE");
  3508. X            wrefresh(win);
  3509. X            continue;
  3510. X        }
  3511. X        buf[0] = (char) i;
  3512. X#ifdef DEBUG
  3513. X        fprintf(stderr, "send_first: got header %02x, %03o, %d\n", buf[0], buf[0], buf[0]);
  3514. X#endif /* DEBUG */
  3515. X
  3516. X        switch (buf[0]) {
  3517. X            case SOH:    /* small block follows */
  3518. X                block_size = 128;
  3519. X                return(0);
  3520. X            case STX:    /* large block follows */
  3521. X                if (max_block == 1024) {
  3522. X                    block_size = 1024;
  3523. X                    return(0);
  3524. X                }
  3525. X                /* FALLTHRU */
  3526. X            default:
  3527. X                err_count++;
  3528. X                clear_line(win, 12, 24, TRUE);
  3529. X                waddstr(win, "BAD HEADER");
  3530. X                wrefresh(win);
  3531. X                    /* read some garbage... */
  3532. X                while(fread_line(buf, 1028, 1) != -1)
  3533. X                    ;
  3534. X                putc_line(NAK);
  3535. X                break;
  3536. X        }
  3537. X    }
  3538. X    beep();
  3539. X    clear_line(win, 12, 24, TRUE);
  3540. X    wattrstr(win, A_BOLD, "TIMED OUT");
  3541. X    wrefresh(win);
  3542. X    return(ERROR);
  3543. X}
  3544. X
  3545. X/*
  3546. X * Receive a block of info from the host.  Returns a 0 on success, a 1 on
  3547. X * a duplicate block or the standard error codes.  The variables
  3548. X * err_method and block_size are global.
  3549. X */
  3550. X
  3551. int
  3552. rcv_block(win, got_hdr, max_block, blk)
  3553. WINDOW *win;
  3554. int got_hdr, max_block;
  3555. unsigned char blk;
  3556. X{
  3557. X    int i, err_count, bad_block, out_of_sync;
  3558. X    unsigned short crc, calc_crc();
  3559. X    unsigned int packet, sleep();
  3560. X    unsigned char blk_compliment, calc_sum(), crc_1, crc_2;
  3561. X    void cancel_xfer();
  3562. X
  3563. X    err_count = 0;
  3564. X    while (err_count < MAX_ERRORS) {
  3565. X        mvwprintw(win, 10, 24, "%-2d", err_count);
  3566. X        mvwprintw(win, 11, 24, "%-3d", tot_err);
  3567. X
  3568. X                    /* scan the keyboard for abort */
  3569. X        if (wgetch(win) == ESC) {
  3570. X            beep();
  3571. X            clear_line(win, 12, 24, TRUE);
  3572. X            waddstr(win, "ABORTED");
  3573. X            wrefresh(win);
  3574. X            cancel_xfer(DOWN_LOAD);
  3575. X            sleep(3);
  3576. X            return(ABORT);
  3577. X        }
  3578. X                    /* have we already got a hdr? */
  3579. X        if (!got_hdr) {
  3580. X            if ((i = getc_line(10)) == -1) {
  3581. X                err_count++;
  3582. X                tot_err++;
  3583. X                clear_line(win, 12, 24, TRUE);
  3584. X                waddstr(win, "NO RESPONSE");
  3585. X                wrefresh(win);
  3586. X                continue;
  3587. X            }
  3588. X            buf[0] = (char) i;
  3589. X#ifdef DEBUG
  3590. X            fprintf(stderr, "rcv_block: got header %02x, %03o, %d\n", buf[0], buf[0], buf[0]);
  3591. X#endif /* DEBUG */
  3592. X                    /* what'd we get? */
  3593. X            switch (buf[0]) {
  3594. X                case EOT:    /* we're done! */
  3595. X                    clear_line(win, 12, 24, TRUE);
  3596. X                    waddstr(win, "TRANSFER COMPLETE");
  3597. X                    wrefresh(win);
  3598. X                    sleep(1);
  3599. X                    return(0);
  3600. X                case SOH:    /* small block follows */
  3601. X                    block_size = 128;
  3602. X                    break;
  3603. X                case STX:    /* large block follows */
  3604. X                    if (max_block == 1024) {
  3605. X                        block_size = 1024;
  3606. X                        break;
  3607. X                    }
  3608. X                    /* FALLTHRU */
  3609. X                default:
  3610. X                    err_count++;
  3611. X                    tot_err++;
  3612. X                    clear_line(win, 12, 24, TRUE);
  3613. X                    waddstr(win, "BAD HEADER");
  3614. X                    wrefresh(win);
  3615. X
  3616. X                    /* read some garbage... */
  3617. X                    while(fread_line(buf, 1028, 1) != -1)
  3618. X                        ;
  3619. X                    putc_line(NAK);
  3620. X                    continue;
  3621. X            }
  3622. X        }
  3623. X                    /* read the rest of the packet */
  3624. X        packet = block_size + 2 + (err_method == CHECKSUM ? 1 : 2);
  3625. X        if (fread_line(&buf[1], packet, 10) == -1) {
  3626. X            clear_line(win, 12, 24, TRUE);
  3627. X            waddstr(win, "TIMED OUT");
  3628. X            wrefresh(win);
  3629. X            putc_line(NAK);
  3630. X            err_count++;
  3631. X            tot_err++;
  3632. X            continue;
  3633. X        }
  3634. X
  3635. X        /*
  3636. X         * Validation of the packet includes checking the
  3637. X         * block number, its complement, and the crc/checksum.
  3638. X         */
  3639. X        out_of_sync = 0;
  3640. X        blk_compliment = ~blk;
  3641. X        if (buf[1] != blk || buf[2] != blk_compliment)
  3642. X            out_of_sync++;
  3643. X
  3644. X        bad_block = 0;
  3645. X        switch (err_method) {
  3646. X            case CHECKSUM:
  3647. X#ifdef DEBUG
  3648. X                fprintf(stderr, "blk=%d, checksum=%d\n", blk, calc_sum(&buf[3], block_size));
  3649. X#endif /* DEBUG */
  3650. X                if (buf[block_size +3] != calc_sum(&buf[3], block_size))
  3651. X                    bad_block++;
  3652. X                break;
  3653. X            case CRC:
  3654. X                crc = calc_crc(&buf[3], block_size);
  3655. X                crc_1 = crc >> 8;
  3656. X                crc_2 = crc & 0xff;
  3657. X#ifdef DEBUG
  3658. X                fprintf(stderr, "blk=%d, crc1=%d, crc2=%d\n", blk, crc_1, crc_2);
  3659. X#endif /* DEBUG */
  3660. X                if (buf[block_size +3] != crc_1 || buf[block_size +4] != crc_2)
  3661. X                    bad_block++;
  3662. X                break;
  3663. X            case NONE:
  3664. X                return(0);
  3665. X        }
  3666. X                    /* handle errors */
  3667. X        if (bad_block) {
  3668. X            clear_line(win, 12, 24, TRUE);
  3669. X            if (err_method == CRC)
  3670. X                waddstr(win, "CRC FAILED");
  3671. X            else
  3672. X                waddstr(win, "CHECKSUM FAILED");
  3673. X            wrefresh(win);
  3674. X            putc_line(NAK);
  3675. X            err_count++;
  3676. X            tot_err++;
  3677. X            continue;
  3678. X        }
  3679. X                    /* not really an error */
  3680. X        if (out_of_sync) {
  3681. X            /*
  3682. X             * If a perfect packet is off by 1 block number,
  3683. X             * (a lost ACK could cause this) then treat it as
  3684. X             * a good block but don't write it to disk.
  3685. X             */
  3686. X            if (buf[1] == (unsigned char) blk-1)
  3687. X                return(1);
  3688. X
  3689. X            clear_line(win, 12, 24, TRUE);
  3690. X            waddstr(win, "OUT OF SYNC");
  3691. X            wrefresh(win);
  3692. X            putc_line(NAK);
  3693. X            err_count++;
  3694. X            tot_err++;
  3695. X            continue;
  3696. X        }
  3697. X        return(0);
  3698. X    }
  3699. X    beep();
  3700. X    clear_line(win, 12, 24, TRUE);
  3701. X    waddstr(win, "TOO MANY ERRORS");
  3702. X    wrefresh(win);
  3703. X    cancel_xfer(DOWN_LOAD);
  3704. X    return(ERROR);
  3705. X}
  3706. END_OF_FILE
  3707. if test 12062 -ne `wc -c <'x_rcv.c'`; then
  3708.     echo shar: \"'x_rcv.c'\" unpacked with wrong size!
  3709. fi
  3710. # end of 'x_rcv.c'
  3711. fi
  3712. if test -f 'x_send.c' -a "${1}" != "-c" ; then 
  3713.   echo shar: Will not clobber existing file \"'x_send.c'\"
  3714. else
  3715. echo shar: Extracting \"'x_send.c'\" \(11671 characters\)
  3716. sed "s/^X//" >'x_send.c' <<'END_OF_FILE'
  3717. X/*
  3718. X * Send a list of files using a version of Ward Christensen's file
  3719. X * transfer protocol.  A non-zero return code means an error must be
  3720. X * acknowledged by the user (a user generated abort returns a 0).
  3721. X */
  3722. X
  3723. X#include <stdio.h>
  3724. X#include <curses.h>
  3725. X#include <sys/types.h>
  3726. X#include <sys/stat.h>
  3727. X#include "config.h"
  3728. X#include "dial_dir.h"
  3729. X#include "misc.h"
  3730. X#include "xmodem.h"
  3731. X
  3732. static int tot_err, err_method;
  3733. static int rcv_first();
  3734. X
  3735. int
  3736. send_xmodem(win, list, type)
  3737. WINDOW *win;
  3738. char *list;
  3739. int type;
  3740. X{
  3741. X    extern char *protocol[];
  3742. X    FILE *fp, *uid_fopen();
  3743. X    int i, block_size, file_count, secs, mins, hours, big_blocks;
  3744. X    int small_blocks, err_count, got_it, num, is_batch, code;
  3745. X    int max_block, default_err;
  3746. X    long size, block, sent, xmit_size;
  3747. X    char *file, *strtok(), *name, *strrchr();
  3748. X    unsigned short crc, calc_crc();
  3749. X    unsigned char buf[1029], blk, calc_sum();
  3750. X    unsigned int packet, sleep();
  3751. X    float performance, percent;
  3752. X    struct stat stbuf;
  3753. X                    /* which protocol? */
  3754. X    switch (type) {
  3755. X        case XMODEM:
  3756. X            is_batch = 0;
  3757. X            default_err = CRC_CHECKSUM;
  3758. X            max_block = 128;
  3759. X            performance = 1.36;
  3760. X            break;
  3761. X        case XMODEM_1k:
  3762. X            is_batch = 0;
  3763. X            default_err = CRC_CHECKSUM;
  3764. X            max_block = 1024;
  3765. X            performance = 1.09;
  3766. X            break;
  3767. X        case MODEM7:
  3768. X            is_batch = 1;
  3769. X            default_err = CHECKSUM;
  3770. X            max_block = 128;
  3771. X            performance = 1.36;
  3772. X            break;
  3773. X        case YMODEM:
  3774. X            is_batch = 1;
  3775. X            default_err = CRC;
  3776. X            max_block = 1024;
  3777. X            performance = 1.09;
  3778. X            break;
  3779. X        case YMODEM_G:
  3780. X            is_batch = 1;
  3781. X            default_err = NONE;
  3782. X            max_block = 1024;
  3783. X            performance = 1.02;
  3784. X            break;
  3785. X        default:
  3786. X            return(1);
  3787. X    }
  3788. X
  3789. X    tot_err = 0;
  3790. X    file_count = 0;
  3791. X    mvwaddstr(win, 2, 24, protocol[type -1]);
  3792. X    mvwaddstr(win, 11, 24, "0  ");
  3793. X
  3794. X                    /* each one in the list */
  3795. X    file = strtok(list, " \t");
  3796. X    do {
  3797. X                    /* is it a batch type? */
  3798. X        file_count++;
  3799. X        if (file_count > 1 && !is_batch)
  3800. X            break;
  3801. X                    /* display the name */
  3802. X        clear_line(win, 3, 24, TRUE);
  3803. X        if ((name = strrchr(file, '/')))
  3804. X            name++;
  3805. X        else
  3806. X            name = file;
  3807. X        waddstr(win, name);
  3808. X        wrefresh(win);
  3809. X                    /* get the file size */
  3810. X        if (stat(file, &stbuf) < 0) {
  3811. X            beep();
  3812. X            clear_line(win, 12, 24, TRUE);
  3813. X            wattrstr(win, A_BOLD, "CAN'T FIND FILE");
  3814. X            wrefresh(win);
  3815. X            sleep(3);
  3816. X            continue;
  3817. X        }
  3818. X                    /* sanity checking */
  3819. X        if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
  3820. X            beep();
  3821. X            clear_line(win, 12, 24, TRUE);
  3822. X            wattrstr(win, A_BOLD, "NOT REGULAR FILE");
  3823. X            wrefresh(win);
  3824. X            sleep(3);
  3825. X            continue;
  3826. X        }
  3827. X
  3828. X        size = stbuf.st_size;
  3829. X        mvwprintw(win, 4, 24, "%-10ld", size);
  3830. X        clear_line(win, 5, 24, TRUE);
  3831. X
  3832. X        if (!(fp = uid_fopen(file, "r"))) {
  3833. X            beep();
  3834. X            clear_line(win, 12, 24, TRUE);
  3835. X            wattrstr(win, A_BOLD, "PERMISSION DENIED");
  3836. X            wrefresh(win);
  3837. X            sleep(3);
  3838. X            continue;
  3839. X        }
  3840. X                    /* get the xmit size */
  3841. X        block_size = max_block;
  3842. X        big_blocks = 0;
  3843. X        small_blocks = 0;
  3844. X        if (block_size == 128) {
  3845. X            small_blocks = size / 128;
  3846. X            if (size % 128)
  3847. X                small_blocks++;
  3848. X        }
  3849. X        else {
  3850. X            big_blocks = size / 1024;
  3851. X            small_blocks = (size % 1024) / 128;
  3852. X            if (size % 128)
  3853. X                small_blocks++;
  3854. X
  3855. X            if (small_blocks == 8 && !big_blocks) {
  3856. X                big_blocks++;
  3857. X                small_blocks = 0;
  3858. X            }
  3859. X                    /* if tiny file */
  3860. X            if (big_blocks == 0)
  3861. X                block_size = 128;
  3862. X        }
  3863. X
  3864. X        xmit_size = ((unsigned int) big_blocks * 1024L) + ((unsigned int) small_blocks * 128L);
  3865. X                    /* add block 0 to the size */
  3866. X        if (type == YMODEM || type == YMODEM_G)
  3867. X            xmit_size += 128L;
  3868. X
  3869. X        secs = (xmit_size * 10.0 / dir->baud[0]) * performance;
  3870. X        hours = secs / 3600;
  3871. X        mins = (secs % 3600) / 60;
  3872. X        secs = (secs % 3600) % 60;
  3873. X
  3874. X        mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
  3875. X
  3876. X                    /* some starting numbers */
  3877. X        mvwaddstr(win, 7, 24, "     ");
  3878. X        mvwaddstr(win, 8, 24, "0%  ");
  3879. X        mvwaddstr(win, 9, 24, "0          ");
  3880. X        mvwaddstr(win, 10, 24, "0 ");
  3881. X        clear_line(win, 12, 24, TRUE);
  3882. X        waddstr(win, "NONE");
  3883. X        wrefresh(win);
  3884. X                    /* send the batch stuff */
  3885. X        switch (type) {
  3886. X            case MODEM7:
  3887. X                if (code = rcv_first(win, default_err)) {
  3888. X                    fclose(fp);
  3889. X                    return(code +1);
  3890. X                }
  3891. X
  3892. X                if (send_modem7(win, name)) {
  3893. X                    fclose(fp);
  3894. X                    return(1);
  3895. X                }
  3896. X                break;
  3897. X            case YMODEM:
  3898. X            case YMODEM_G:
  3899. X                if (code = rcv_first(win, default_err)) {
  3900. X                    fclose(fp);
  3901. X                    return(code +1);
  3902. X                }
  3903. X
  3904. X                if (code = send_ymodem(win, name, size)) {
  3905. X                    fclose(fp);
  3906. X                    /*
  3907. X                     * CANCEL now means that the other
  3908. X                     * end can't open that file.
  3909. X                     */
  3910. X                    if (code == CANCEL)
  3911. X                        break;
  3912. X                    return(code +1);
  3913. X                }
  3914. X                xmit_size -= 128L;
  3915. X                break;
  3916. X            default:
  3917. X                code = 0;
  3918. X                break;
  3919. X        }
  3920. X                    /* remote can't receive that file? */
  3921. X        if (code == CANCEL)
  3922. X            break;
  3923. X                    /* wait for first character */
  3924. X        if (code = rcv_first(win, default_err)) {
  3925. X            fclose(fp);
  3926. X            return(code +1);
  3927. X        }
  3928. X                    /* here we go... */
  3929. X        clear_line(win, 12, 24, TRUE);
  3930. X        waddstr(win, "NONE");
  3931. X        wrefresh(win);
  3932. X        sent = 0L;
  3933. X        block = 1L;
  3934. X        blk = 1;
  3935. X        while (num = fread((char *) &buf[3], sizeof(char), block_size, fp)) {
  3936. X
  3937. X                    /* fill short block */
  3938. X            if (num < block_size) {
  3939. X                for (i=num; i<block_size; i++)
  3940. X                    buf[i+3] = CTRLZ;
  3941. X            }
  3942. X
  3943. X                    /* show current stats */
  3944. X            mvwprintw(win, 7, 24, "%-5ld", block);
  3945. X            percent = sent * 100.0 / xmit_size;
  3946. X            mvwprintw(win, 8, 24, "%0.1f%%", percent);
  3947. X            mvwprintw(win, 9, 24, "%-10ld", sent);
  3948. X            wrefresh(win);
  3949. X
  3950. X                    /* build the header */
  3951. X            if (block_size == 128)
  3952. X                buf[0] = SOH;
  3953. X            else
  3954. X                buf[0] = STX;
  3955. X
  3956. X            buf[1] = blk;
  3957. X            buf[2] = ~blk;
  3958. X
  3959. X                    /* build the error detection stuff */
  3960. X            switch (err_method) {
  3961. X                case CHECKSUM:
  3962. X                    buf[block_size+3] = calc_sum(&buf[3], block_size);
  3963. X#ifdef DEBUG
  3964. X                    fprintf(stderr, "blk=%d, checksum=%d\n", blk, buf[block_size+3]);
  3965. X#endif /* DEBUG */
  3966. X                    packet = block_size +4;
  3967. X                    break;
  3968. X                case CRC:
  3969. X                    crc = calc_crc(&buf[3], block_size);
  3970. X                    buf[block_size+3] = crc >> 8;
  3971. X                    buf[block_size+4] = crc & 0xff;
  3972. X#ifdef DEBUG
  3973. X                    fprintf(stderr, "blk=%d, crc1=%d, crc2=%d\n", blk, buf[block_size+3], buf[block_size+4]);
  3974. X#endif /* DEBUG */
  3975. X                    packet = block_size +5;
  3976. X                    break;
  3977. X                case NONE:
  3978. X                    buf[block_size+3] = 0;
  3979. X                    buf[block_size+4] = 0;
  3980. X                    packet = block_size +5;
  3981. X                    break;
  3982. X            }
  3983. X
  3984. X                    /* send the block */
  3985. X            if (code = send_block(win, buf, packet)) {
  3986. X                fclose(fp);
  3987. X                return(code +1);
  3988. X            }
  3989. X            block++;
  3990. X            blk++;
  3991. X            sent = sent + (unsigned int) block_size;
  3992. X
  3993. X                    /* change block size? */
  3994. X            if (xmit_size - sent < 1024)
  3995. X                block_size = 128;
  3996. X        }
  3997. X        mvwaddstr(win, 8, 24, "100%  ");
  3998. X        mvwprintw(win, 9, 24, "%-10ld", sent);
  3999. X                    /* at the end of the file */
  4000. X        err_count = 0;
  4001. X        got_it = 0;
  4002. X        while (err_count < MAX_ERRORS) {
  4003. X            putc_line(EOT);
  4004. X            if (getc_line(10) == ACK) {
  4005. X                got_it++;
  4006. X                break;
  4007. X            }
  4008. X            err_count++;
  4009. X        }
  4010. X        clear_line(win, 12, 24, TRUE);
  4011. X        if (!got_it) {
  4012. X            /*
  4013. X             * So what???  We don't do anything if there is
  4014. X             * no acknowledge from the host!!
  4015. X             */
  4016. X            waddstr(win, "NO ACKNOWLEDGE");
  4017. X        }
  4018. X        else
  4019. X            waddstr(win, "TRANSFER COMPLETE");
  4020. X        if (!is_batch)
  4021. X            beep();
  4022. X        wrefresh(win);
  4023. X        sleep(2);
  4024. X                    /* prepare to start again */
  4025. X        fclose(fp);
  4026. X    } while (file = strtok((char *) NULL, " \t"));
  4027. X
  4028. X    /*
  4029. X     * The end of batch markers... For modem7 it's an ACK and EOT, for
  4030. X     * ymodem, it's an empty block 0.
  4031. X     */
  4032. X    switch (type) {
  4033. X        case MODEM7:
  4034. X            if (code = rcv_first(win, default_err))
  4035. X                return(code +1);
  4036. X            putc_line(ACK);
  4037. X            putc_line(EOT);
  4038. X            beep();
  4039. X            wrefresh(win);
  4040. X            break;
  4041. X        case YMODEM:
  4042. X        case YMODEM_G:
  4043. X            if (code = rcv_first(win, default_err))
  4044. X                return(code +1);
  4045. X
  4046. X            if (code = send_ymodem(win, "", 0L))
  4047. X                return(code +1);
  4048. X            beep();
  4049. X            wrefresh(win);
  4050. X            break;
  4051. X        default:
  4052. X            break;
  4053. X    }
  4054. X    return(0);
  4055. X}
  4056. X
  4057. X/*
  4058. X * Wait for the first character to start the transmission.  This first
  4059. X * character also sets the crc/checksum method.  Returns the standard
  4060. X * error codes, or 0 on success.  The variable err_method is global.
  4061. X */
  4062. X
  4063. static int
  4064. rcv_first(win, default_err)
  4065. WINDOW *win;
  4066. int default_err;
  4067. X{
  4068. X    int i, err_count;
  4069. X    unsigned int sleep();
  4070. X    void cancel_xfer();
  4071. X
  4072. X    err_count = 0;
  4073. X    while (err_count < MAX_ERRORS) {
  4074. X
  4075. X                    /* scan the keyboard for abort */
  4076. X        if (wgetch(win) == ESC) {
  4077. X            beep();
  4078. X            clear_line(win, 12, 24, TRUE);
  4079. X            waddstr(win, "ABORTED");
  4080. X            wrefresh(win);
  4081. X            cancel_xfer(UP_LOAD);
  4082. X            sleep(3);
  4083. X            return(ABORT);
  4084. X        }
  4085. X                    /* scan the TTY line */
  4086. X        i = getc_line(10);
  4087. X#ifdef DEBUG
  4088. X        fprintf(stderr, "rcv_first: got \"%c\", %02x, %03o, %d\n", i, i, i, i);
  4089. X#endif /* DEBUG */
  4090. X        switch (i) {
  4091. X            case -1:    /* timed out */
  4092. X                clear_line(win, 12, 24, TRUE);
  4093. X                wattrstr(win, A_BOLD, "NO RESPONSE");
  4094. X                err_count++;
  4095. X                break;
  4096. X            case NAK:    /* checksum marker */
  4097. X                if (default_err == CHECKSUM || default_err == CRC_CHECKSUM) {
  4098. X                    mvwaddstr(win, 5, 24, "CHECKSUM");
  4099. X                    err_method = CHECKSUM;
  4100. X                    return(0);
  4101. X                }
  4102. X                err_count++;
  4103. X                break;
  4104. X            case 'C':    /* CRC marker */
  4105. X                if (default_err == CRC_CHECKSUM || default_err == CRC) {
  4106. X                    mvwaddstr(win, 5, 24, "CRC");
  4107. X                    err_method = CRC;
  4108. X                    return(0);
  4109. X                }
  4110. X                err_count++;
  4111. X                break;
  4112. X            case 'G':    /* ymodem-g marker */
  4113. X                if (default_err == NONE) {
  4114. X                    mvwaddstr(win, 5, 24, "NONE");
  4115. X                    err_method = NONE;
  4116. X                    return(0);
  4117. X                }
  4118. X                err_count++;
  4119. X                break;
  4120. X            case CAN:    /* two CAN's and you're out! */
  4121. X                if (getc_line(2) == CAN) {
  4122. X                    beep();
  4123. X                    clear_line(win, 12, 24, TRUE);
  4124. X                    wattrstr(win, A_BOLD, "REMOTE ABORTED");
  4125. X                    wrefresh(win);
  4126. X                    return(CANCEL);
  4127. X                }
  4128. X                err_count++;
  4129. X                break;
  4130. X            default:
  4131. X                clear_line(win, 12, 24, TRUE);
  4132. X                waddstr(win, "BAD HEADER");
  4133. X                err_count++;
  4134. X                break;
  4135. X        }
  4136. X        mvwprintw(win, 10, 24, "%-2d", err_count);
  4137. X        wrefresh(win);
  4138. X    }
  4139. X                    /* failed to get it right? */
  4140. X    beep();
  4141. X    clear_line(win, 12, 24, TRUE);
  4142. X    wattrstr(win, A_BOLD, "TIMED OUT");
  4143. X    wrefresh(win);
  4144. X    return(ERROR);
  4145. X}
  4146. X
  4147. X/*
  4148. X * Send a block of data, scan the keyboard for a user abort, and check
  4149. X * the return codes from the host.  Returns standard error codes or 0
  4150. X * on success.
  4151. X */
  4152. X
  4153. int
  4154. send_block(win, blk, packet)
  4155. WINDOW *win;
  4156. unsigned char *blk;
  4157. unsigned int packet;
  4158. X{
  4159. X    extern int fd;
  4160. X    int i, err_count;
  4161. X    void cancel_xfer();
  4162. X    unsigned int sleep();
  4163. X
  4164. X    err_count = 0;
  4165. X    mvwaddstr(win, 10, 24, "0 ");
  4166. X
  4167. X    while (err_count < MAX_ERRORS) {
  4168. X                    /* write the block */
  4169. X        write(fd, (char *) blk, packet);
  4170. X                    /* scan the keyboard for abort */
  4171. X        if (wgetch(win) == ESC) {
  4172. X            beep();
  4173. X            clear_line(win, 12, 24, TRUE);
  4174. X            waddstr(win, "ABORTED");
  4175. X            wrefresh(win);
  4176. X            cancel_xfer(UP_LOAD);
  4177. X            sleep(3);
  4178. X            return(ABORT);
  4179. X        }
  4180. X                    /* ymodem-g doesn't need ACKs */
  4181. X        if (err_method == NONE)
  4182. X            return(0);
  4183. X                    /* wait for acknowledge */
  4184. X        i = getc_line(10);
  4185. X#ifdef DEBUG
  4186. X        fprintf(stderr, "send_block: got \"%c\", %02x, %03o, %d\n", i, i, i, i);
  4187. X#endif /* DEBUG */
  4188. X        switch (i) {
  4189. X            case -1:    /* timed out */
  4190. X                clear_line(win, 12, 24, TRUE);
  4191. X                waddstr(win, "NO RESPONSE");
  4192. X                err_count++;
  4193. X                tot_err++;
  4194. X                break;
  4195. X            case ACK:    /* Hooray!! we got it */
  4196. X                return(0);
  4197. X            case NAK:    /* show our disappointment... */
  4198. X                clear_line(win, 12, 24, TRUE);
  4199. X                if (err_method == CRC)
  4200. X                    waddstr(win, "CRC FAILED");
  4201. X                else
  4202. X                    waddstr(win, "CHECKSUM FAILED");
  4203. X                err_count++;
  4204. X                tot_err++;
  4205. X                break;
  4206. X            case CAN:    /* two CAN's and you're out! */
  4207. X                if (getc_line(2) == CAN) {
  4208. X                    beep();
  4209. X                    clear_line(win, 12, 24, TRUE);
  4210. X                    wattrstr(win, A_BOLD, "REMOTE ABORTED");
  4211. X                    wrefresh(win);
  4212. X                    return(CANCEL);
  4213. X                }
  4214. X                /* FALLTHRU */
  4215. X            default:
  4216. X                clear_line(win, 12, 24, TRUE);
  4217. X                waddstr(win, "RESENDING");
  4218. X                err_count++;
  4219. X                tot_err++;
  4220. X                break;
  4221. X        }
  4222. X                    /* flush any pending garbage */
  4223. X        tty_flush(fd, 0);
  4224. X
  4225. X        mvwprintw(win, 10, 24, "%-2d", err_count);
  4226. X        mvwprintw(win, 11, 24, "%-3d", tot_err);
  4227. X        wrefresh(win);
  4228. X    }
  4229. X                    /* failed to get it right */
  4230. X    beep();
  4231. X    clear_line(win, 12, 24, TRUE);
  4232. X    wattrstr(win, A_BOLD, "TOO MANY ERRORS");
  4233. X    wrefresh(win);
  4234. X    cancel_xfer(UP_LOAD);
  4235. X    return(ERROR);
  4236. X}
  4237. END_OF_FILE
  4238. if test 11671 -ne `wc -c <'x_send.c'`; then
  4239.     echo shar: \"'x_send.c'\" unpacked with wrong size!
  4240. fi
  4241. # end of 'x_send.c'
  4242. fi
  4243. echo shar: End of archive 4 \(of 6\).
  4244. cp /dev/null ark4isdone
  4245. MISSING=""
  4246. for I in 1 2 3 4 5 6 ; do
  4247.     if test ! -f ark${I}isdone ; then
  4248.     MISSING="${MISSING} ${I}"
  4249.     fi
  4250. done
  4251. if test "${MISSING}" = "" ; then
  4252.     echo You have unpacked all 6 archives.
  4253.     rm -f ark[1-9]isdone
  4254. else
  4255.     echo You still need to unpack the following archives:
  4256.     echo "        " ${MISSING}
  4257. fi
  4258. ##  End of shell archive.
  4259. exit 0
  4260.