File: ckcplm.doc

package info (click to toggle)
ckermit 193-3
  • links: PTS
  • area: non-free
  • in suites: slink
  • size: 6,180 kB
  • ctags: 8,803
  • sloc: ansic: 118,504; makefile: 2,474; sh: 52
file content (1996 lines) | stat: -rw-r--r-- 87,670 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
CKCPLM.DOC                                                            May 1998

			C-KERMIT PROGRAM LOGIC MANUAL

As of C-Kermit version:  6.1.193 Beta.04
This file last updated:  Sun May  3 19:36:59 1998
Author: Frank da Cruz, Columbia University
E-Mail: fdc@columbia.edu
  
  Copyright (C) 1985, 1998, Trustees of Columbia University in the City of New
  York.  The C-Kermit software may not be, in whole or in part, licensed or
  sold for profit as a software product itself, nor may it be included in or
  distributed with commercial products or otherwise distributed by commercial
  concerns to their clients or customers without written permission of the
  Office of Kermit Development and Distribution, Columbia University.  This
  copyright notice must not be removed, altered, or obscured.


INTRODUCTION

The Kermit Protocol is specified in the book "Kermit, A File Transfer
Protocol" by Frank da Cruz, Digital Press / Butterworth Heinemann, Newton, MA,
USA (1987), 379 pages, ISBN 0-932376-88-6.  It is assumed the reader is
familiar with the Kermit protocol specification.

This file attempts to describe the relationship among the modules and
functions of C-Kermit 5A and 6.x.  Before reading this file, please read the
file CKAAAA.HLP for an overview of C-Kermit file naming conventions.

C-Kermit is designed to be portable to any kind of computer that has a C
compiler.  The source code is broken into many files that are grouped
according to their function.  There are several major groups: 1 (the protocol
kernel), 2 (the user interface), 3 (system-dependent primitives), 4 (network
support), and 5 (formatted screen support).


CONTENTS:

  FILES
  SOURCE CODE PORTABILITY GUIDE

  GROUP 1    System-independent file transfer protocol
  GROUP 1.5  Character set translation
  GROUP 2    User Interface
  GROUP 3    File & communications i/o and other system dependencies
  GROUP 4    Network support
  GROUP 5    Formatted screen support

  APPENDIX I File Protections

WARNING: C-Kermit 6.1 is probably the last version preserving this
organization and naming.  The next major release after 6.1 will apply some
lessons we have learned about modularity and separation, and allow easier
integration of the code with other applications and/or user interfaces.


FILES

C-Kermit source files begin with the two letters CK (lowercase on UNIX
systems, uppercase on most others).  The third character denotes something
about the function group and the expected level of portability.  See the file
CKAAAA.HLP for details of file naming conventions and organization.

One hint before proceeding: functions are scattered all over the ckc*.c
and ckuu*.c modules, where function size has begun to take precedence over
the desirability of grouping related functions together, the aim being to
keep any particular module from growing disproportionately large.  The easiest
way (in UNIX) to find out what source file a given function is defined in is
like this (where the desired function is foo()...):

  grep ^foo ck*.c

This works because the coding convention has been to make function names
always start on the left margin with their contents indented, for example:

static char *
foo(x,y) int x, y; {
    ...
}

Also please note the style for bracket placement.  This allows
bracket-matching text editors (such as EMACS) to help you make sure you know
which opening bracket a closing bracket matches, particularly when it is no
longer visible on the screen, and it also makes it easy to find the end of a
function (search for '}' on the right margin).

Of course EMACS tags work nicely with this format too:

  $ cd <kermit-source-directory>
  $ etags ck[cuw]*.[cwh]
  $ emacs
  Esc-X Visit-Tags-Table<CR><CR>


SOURCE CODE PORTABILITY GUIDE

When writing code for the system-indendent C-Kermit modules, please stick to
the following coding conventions to ensure portability to the widest possible
variety of C preprocessors, compilers, and linkers, as well as certain network
and/or email transports:

. Tabs should be set every 8 spaces, as on a VT100.
. All lines must no more than 79 characters wide after tab expansion.
. Note the distinction between physical tabs (ASCII 9) and the indentation
  conventions, which are: 4 for block contents, 2 for most other stuff.
. Try to keep variable and function names unique within 6 characters,
  especially if they are used across modules, since 6 is the maximum for
  some linkers.  (Actually, I think the last system that had this limitation
  was turned off in the 1980s -- remember SIXBIT? -- no now maybe it's 8?)
. Keep preprocessor symbols unique within 8 characters.
. Don't put #include directives inside functions or { blocks }.
. Don't use the #if preprocessor construction, only use #ifdef, #ifndef, #undef
. Put tokens after #endif in comment brackets, e.g. #endif /* FOO */.
. Don't indent preprocessor statements - # must always be first char on line.
. Don't put whitespace after # in preprocessor statements.
. Don't use #pragma, even within #ifdefs - it makes some preprocessors give up.
. Same goes for #module, #if, etc - #ifdefs do NOT protect them.
. Don't use logical operators in preprocessor constructions.
. Always cast strlen() in expressions to int: "if ((int)strlen(foo) < x)...".
. Any variable whose value might exceed 16383 should be declared as long,
  or if that is not possible, then as unsigned.
. Don't use initializers with automatic arrays.
. Don't assume that struct assignment performs a copy.
. Don't put prototypes for static functions into header files that are used
  by modules that don't contain that function.
. Avoid the construction *++p -- the order of evaluation varies.
. Reportedly, some compilers even mess up with *(++p).
. Don't use triple assignments, like a = b = c = 0; (or quadruple, etc).
  Some compilers generate bad code for these, or crash, etc.
. Structure members may not have the same names as other identifiers.
. Avoid huge switch() statements with many cases.
. Don't have a switch() statement with no cases (e.g. because of #ifdefs).
. Don't put anything between "switch() {" and case:.  Some compilers do not
  treat switch blocks like other blocks.
. Don't make character-string constants longer than about 250.
. Don't write into character-string constants even when you know you are not
  writing past the end because the compiler or linker might have put them into
  read-only and/or shared memory, and/or coalesced multiple equal constants
  so if you change one you change them all.
. Don't depend on '\r' being carriage return.
. Don't depend on '\n' being linefeed or for that matter any SINGLE character.
. Don't depend on '\r' and '\n' being different (e.g. in switch() statements).
. In other words, don't use \n or \r to stand for specific characters;
  use \012 and \015 instead.
. Don't code for "buzzword 1.0 compliance", unless "buzzword" is K&R and
  "1.0" is the first edition.
. Don't use or depend on anything_t (size_t, time_t, etc).
. Don't use or depend on internationalization ("i18n") features, wchar_t,
  locales, etc, in portable code; they are not portable.  Anyway, locales are
  not the right model for Kermit's multi-character-set support.
. Don't make any assumption about signal handler type.  It can be void, int,
  long, or anything else.  Always declare signal handlers as SIGTYP (see
  definition in ckcdeb.h and augment it if necessary) and always use
  SIGRETURN at exit points from signal handlers.
. Signals should always be re-armed to be used again (this barely scratches
  the surface -- the difference between BSD/V7 and System V and POSIX signal
  handling are numerous, and some platforms do not even support signals,
  alarms, or longjmps correctly or at all -- avoid all of this stuff if you
  can).
. memset(), memmove(), and memcpy() are not portable, don't use them without
  protecting them in ifdefs.  bzero() too, except we're guaranteed to have
  bzero() when using the sockets library.  See examples in the source.
. Don't assume that strncpy() stops on the first null byte -- some versions
  always copy the number of bytes given in arg 3.  Probably also true of
  other strnblah() functions.
. DID YOU KNOW.. that some versions of inet_blah() routines return IP addresses
  in network byte order, while others return them local machine byte order?
  So passing them to htons(), etc, is not always the right thing to do.
. Don't use ANSI-format function declarations without #ifdef CK_ANSIC,
  and always provide an #else for the non-ANSI case.
. Don't depend on any other ANSI preprocessor features like "pasting" -- they
  are often missing or nonoperational.
. Don't assume any C++ syntax or semantics.
. Don't declare a string as "char foo[]" in one module and "extern char * foo"
  in another, or vice-versa.
. With compiler makers falling all over themselves trying to outdo each other
  in ANSI strictness, it has become increasingly necessary to cast EVERYTHING.
. a[x], where x is an unsigned char, can produce a wild memory reference if x,
  when promoted to an int, becomes negative.  Cast it to (unsigned), even
  though it ALREADY IS unsigned.
. Be careful how you declare functions that have char or long arguments;
  for ANSI compilers you MUST use ANSI declarations to avoid promotion
  problems, but you can't use ANSI declarations with non-ANSI compilers.
  Thus declarations of such functions must be hideously entwined in #ifdefs.
  Example of the latter:

  int			       /*  Put character in server command buffer  */
  #ifdef CK_ANSIC
  putsrv(char c)
  #else
  putsrv(c) char c;
  #endif /* CK_ANSIC */
  /* putsrv */ {
      *srvptr++ = c;
      *srvptr = '\0';		/* Make sure buffer is null-terminated */
      return(0);
  }

. Be careful how you return characters from functions that return int values --
  "getc-like functions" -- in the ANSI world.  Unless you explicitly cast the
  return value to (unsigned), it is likely to be "promoted" to an int and have
  its sign extended.

(many, many more...  This section needs massive filling in.)

C-Kermit needs constant adjustment to new OS and compiler releases.  Every
new release shuffles header files or their contents, or prototypes, or data
types, or levels of ANSI strictness, etc.  Every time you make an adjustment
to remove a new compilation error, BE VERY CAREFUL to #ifdef it on a symbol
unique to the new configuration so that the previous configuration (and all
other configurations on all other platforms) remain as before.

Assume nothing.  Don't assume header files are where they are supposed to be,
that they contain what you think they contain, that they define specific
symbols to have certain values -- or define them at all!  Don't assume system
header files protect themselves against multiple inclusion.  Don't assume that
particular system or library calls are available, or that the arguments are
what you think they are -- order, data type, passed by reference vs value,
etc.  Be very conservative when attempting to write portable code.  Avoid all
advanced features.  Stick with K&R First Edition, and even then you're on
shaky ground.

If you see something that does not make sense, don't assume it's a mistake --
it is probably there for a reason, and changing it or removing is very likely
to cause compilation, linking, or runtime failures sometime, somewhere.  Some
huge percentage of the code, especially in the system-dependent modules, is
workarounds for compiler, linker, or API bugs.

BUT... feel free to violate any or all of these rules in system-specific
modules for environments in which the rules are certain not to apply.  For
example, in VMS-specific code, it is OK to use #if.  But even then, allow for
different compilers or compiler versions used in that same environment,
e.g. VAX C vs DEC C vs GNU C.

THE "CHAR" VS "UNSIGNED CHAR" DILEMMA

This is one of the most aggravating and vexing things about C.  By default,
chars (and char *'s) are SIGNED.  But in the modern era, we need to process
characters that can have 8-bit values, such as ISO Latin-1, IBM CP 850, and
other 8-bit (or 16-bit, etc) character sets, and so this data MUST be treated
as unsigned.  BUT...  Some C compilers (such as those based on the Bell UNIX
V7 compiler) do not support "unsigned char" as a data type.  Therefore we have
the macro or typedef CHAR, which we use when we need chars to be unsigned, but
which, unfortunately, resolves itself to "char" on those compilers that don't
support "unsigned char".  AND SO...  We have to do a lot of fiddling at
runtime to avoid sign extension and so forth.  BUT THAT'S NOT ALL...  Now some
modern compilers (e.g. IBM, DEC, Microsoft) have switches that say "make all
chars be unsigned" (e.g. GNU cc "-funsigned-char").  We use these switches
when they are available.  Other compilers don't have these, and at the same
time, are becoming increasingly strict about type mismatches, and spew out
torrents of warnings when we use a CHAR where a char is expected, or vice
versa.  We fix these one by one using casts, and the code becomes increasingly
ugly.  But there remains a serious problem, namely that certain library and
kernel functions have arguments that are declared as signed chars (or pointers
to them), whereas our character data is unsigned.  Fine, we can can use casts
here too -- but who knows what happens inside these routines.

GROUP 1:

The Kermit protocol kernel.  The filenames start with CKC.  C means that these
files are supposed to be totally portable C, and are expected to compile
correctly on any operating system.  "Portable" does not mean the same as as
"ANSI" -- these modules must compile on 10- and 20-year old computers, with C
preprocessors, compilers, and/or linkers that have all sorts of restrictions.
The group 1 modules do not include any header files other than those that
come with Kermit itself.  They do not contain any library calls (like printf)
or any system calls (like open, close, read, write).  Files:

  CKCSYM.H - For use by C compilers that don't allow -D on the command line.
  CKCASC.H - ASCII character symbol definitions.
  CKCSIG.H - System-independent signal-handling definitions and prototypes.
  CKCDEB.H - Originally, debugging definitions.  Now this file also contains
	     all definitions and prototypes that are shared by all modules in
             all groups. 
  CKCKER.H - Kermit protocol symbol definitions.
  CKCNET.H - Network-related symbol definitions.
  CKCXLA.H - Character-set-related symbol definitions (see next section).

  CKCMAI.C - The main program.  This module contains the declarations of all
  the protocol-related global variables that are shared among the other
  modules.

  CKCPRO.W - The protocol module itself, written in "wart", a lex-like
  preprocessor that is distributed with Kermit under the name CKWART.C.

  CKCFN*.C - The protocol support functions used by the protocol module.

Group 1 modules may call upon functions from Group 3 modules, but not from
Group 2 modules (with the single exception that the main program invokes the
user interface, which is in Group 2).  (This last assertion is really only a
conjecture.)

GROUP 1.5

Character set translation tables and functions.  Used by the Group I protocol
modules, but may be specific to different computers.  (So far, all character
character sets supported by C-Kermit are supported in CKUXLA.C and CKUXLA.H,
including Macintosh and IBM character sets).  These modules should be
completely portable, and not rely on any kind of system or library services.

  CKCXLA.H - Character-set definitions usable by all versions of C-Kermit.
  CK?XLA.H - Character-set definitions for computer "?", e.g. U for UNIX.

  CK?XLA.C - Character-set translation tables and functions for computer "?",
  For example, CKUXLA.C for UNIX, CKMXLA.C for Macintosh.  So far, these are
  the only two such modules.  The UNIX module is used for all versions of
  C-Kermit except the Macintosh version.

  Used for file transfer (SEND, RECEIVE, GET, REMOTE, etc), TRANSMIT,
  CONNECT, etc.

  Here's how to add a new file character set.  Assuming it is based on the
  Roman (Latin) alphabet.  Let's call it "Barbarian".  First, in CK?XLA.H,
  add a definition for FC_BARBA (8 chars maximum length) and increase
  MAXFCSETS by 1.  Then, in CK?XLA.C:

  . Add a barbarian entry into the fcsinfo array.
  . Add a "barbarian" entry to file character set keyword table, fcstab.
  . Add a "barbarian" entry to terminal character set keyword table, ttcstab.
  . Add a translation table from Latin-1 to barbarian: yl1ba[].
  . Add a translation table from barbarian to Latin-1: ybal1[].
  . Add a translation function from Barbarian to ASCII: xbaas().
  . Add a translation function from Barbarian to Latin-1: xbal1().
  . Add a translation function from Latin-1 to Barbarian: xl1ba().
  .  etc etc for each transfer character set...
  . Add translation function pointers to the xls and xlr tables.

  Other translations involving Barbarian (e.g. from Barbarian to
  Latin-Cyrillic) are performed through these tables and functions.  See
  CKUXLA.H and CKUXLA.C for extensive examples.

GROUP 2:

The user interface.  This is the code that communicates with the user, gets
her commands, informs her of the results.  It may be command-line oriented,
interactive prompting dialog, menus and arrow keys, windows and mice, speech
recognition, telepathy, etc.  The user interface has three major functions:

1. Sets the parameters for the file transfer and then starts it.  This is done
by setting certain (many) global variables, such as the protocol machine start
state, the file specification, file type, communication parameters, packet
length, window size, character set, etc.

2. Displays messages on the user's screen during the file transfer, using the
screen() function, which is called by the group-1 modules.

3. Executes any commands directly that do not require Kermit protocol, such
as the CONNECT command, local file management commands, parameter-setting
commands, etc.

If you plan to imbed the Group 1 files into a program with a different user
interface, your interface must supply an appropriate screen() function, plus a
couple related ones like chkint() and intmsg() for handling keyboard (or
mouse, etc) interruptions during file transfer.  The best way to find out
about this is to link all the C-Kermit modules together except the CKUU*.O
and CKUCON.O modules, and see which missing symbols turn up.

C-Kermit's character-oriented user interface (as opposed to the Macintosh
version's graphical user interface) consists of the following modules.
C-Kermit can be built with an interactive command parser, a command-line-
option-only parser, a graphical user interface, or any combination, and it
can even be built with no user interface at all (in which case it runs as a
remote-mode Kermit server).

  CKUUSR.H - Definitions of symbols used in Kermit's commands.

  CKUUSR.H, CKUUSR.C, CKUUS2.C, CKUUS3.C, CKUUS4.C, CKUUS5.C, ... -
  Kermit's interactive command parser, including the script programming
  language.

  CKUUSY.C - The command-line-option parser.

  CKUUSX.C - Functions that are common to both the interactive and 
  command-line parsers.

  CKUCMD.H, CKUCMD.C - The command parsing primitives used by the
  interactive command parser to parse keywords, numbers, filenames, etc,
  and to give help, complete fields, supply defaults, allow abbreviations
  and editing, etc.  This package is totally independent of Kermit, but
  does depend on the Group 3 functions.

  CKUVER.H - Version heralds for different implementations.

  CKUSCR.C - The (old, uucp-like) SCRIPT command.
  CKUDIA.C - The DIAL command.  Includes specific knowledge of many
             types of modems.

  CK?CON.C - The CONNECT command.  Terminal connection, and in some cases
             (Macintosh, OS/2, etc) also terminal emulation.  NOTE: As of
             C-Kermit 6.1, there are two different CONNECT modules for UNIX:
             ckucon.c -- the regular, portable version -- and ckucns.c, a
             new version that uses select() rather than forks so it can handle
             encryption.  But select() is not portable.

For other implementations, the files may, and probably do, have different
names.  For example, the Macintosh graphical user interface filenames start
with CKM.  OS/2 uses the CKUCMD and CKUUS* modules, but has its own CONNECT
command in CKOCON.C.  And so on.

Here is a brief description of C-Kermit's "user interface interface", from 
CKUUSR.C.  It is nowhere near complete; in particular, hundreds of global
variables are shared among the many modules.  These should, some day, be
collected into classes or structures that can be passed around as needed;
not only for purity's sake, but also to allow for multiple simultaneous
communication sessions and or user interfaces.

The ckuus*.c modules depend on the existence of C library features like fopen,
fgets, feof, (f)printf, argv/argc, etc.  Other functions that are likely to
vary among operating systems -- like setting terminal modes or interrupts --
are invoked via calls to functions that are defined in the system-dependent
modules, ck?[ft]io.c.  The command line parser processes any arguments found
on the command line, as passed to main() via argv/argc.  The interactive
parser uses the facilities of the cmd package (developed for this program, but
usable by any program).  Any command parser may be substituted for this one.
The only requirements for the Kermit command parser are these:

1. Set parameters via global variables like duplex, speed, ttname, etc.  See
   ckcmai.c for the declarations and descriptions of these variables.

2. If a command can be executed without the use of Kermit protocol, then
   execute the command directly and set the variable sstate to 0.  Examples
   include 'set' commands, local directory listings, the 'connect' command.

3. If a command requires the Kermit protocol, set the following variables:

   sstate                             string data
     'x' (enter server mode)            (none)
     'r' (send a 'get' command)         cmarg, cmarg2
     'v' (enter receive mode)           cmarg2
     'g' (send a generic command)       cmarg
     's' (send files)                   nfils, cmarg & cmarg2 OR cmlist
     'c' (send a remote host command)   cmarg

   cmlist is an array of pointers to strings.
   cmarg, cmarg2 are pointers to strings.
   nfils is an integer.

   cmarg can be a filename string (possibly wild), or
      a pointer to a prefabricated generic command string, or
      a pointer to a host command string.
   cmarg2 is the name to send a single file under, or
      the name under which to store an incoming file; must not be wild.
      If it's the name for receiving, a null value means to store the
      file under the name it arrives with.
   cmlist is a list of nonwild filenames, such as passed via argv.
   nfils is an integer, interpreted as follows:
     -1: filespec (possibly wild) in cmarg, must be expanded internally.
      0: send from stdin (standard input).
     >0: number of files to send, from cmlist.

The screen() function is used to update the screen during file transfer.
The tlog() function writes to a transaction log (if TLOG is defined).
The debug() function writes to a debugging log (if DEBUG is defined).
The intmsg() and chkint() functions provide the user i/o for interrupting
file transfers.

GROUP 3:

System-dependent function definitions.  All the Kermit modules, including the
command package, call upon these functions, which are designed to provide
system-independent primitives for controlling and manipulating devices and
files.  For UNIX, these functions are defined in the files CKUFIO.C (files),
CKUTIO.C (communication devices), and CKUSIG.C (signal handling).

For VMS, the files are CKVFIO.C, CKVTIO.C, and CKUSIG.C (VMS can use the same
signal handling routines as UNIX).  For OS/2, CKOFIO.C, CKOTIO.C, CKOSIG.C
(OS/2 has its own signal handling).  It doesn't really matter what the files
are called, except for Kermit distribution purposes (grouping related files
together alphabetically), only that each function is provided with the name
indicated, observes the same calling and return conventions, and has the same
type.

The Group 3 modules contain both functions and global variables that are
accessed by modules in the other groups.  These are now described.  Changes
since version 4E of C-Kermit are flagged by the symbol *NEW* (use grep).

(By the way, I got this list by linking all the C-Kermit modules together
except CKUTIO and CKUFIO.  These are the symbols that ld reported as undefined)

A. Variables:

char *DELCMD;
  Pointer to string containing command for deleting files.
  Example: char *DELCMD = "rm -f ";  (UNIX)
  Example: char *DELCMD = "delete "; (VMS)
  Note trailing space.  Filename is concatenated to end of this string.

char *DIRCMD;
  Pointer to string containing command for listing files when a filespec
  is given.
  Example: char *DIRCMD = "/bin/ls -l "; (UNIX)
  Example: char *DIRCMD = "directory ";  (VMS)
  Note trailing space.  Filename is concatenated to end of this string.

char *DIRCM2;   *NEW*
  Pointer to string containing command for listing files when a filespec
  is not given.  (currently not used, handled in another way.)
  Example: char *DIRCMD = "/bin/ls -ld *";
  
char *PWDCMD;
  Pointer to string containing command to display current directory.
  Example: char *PWDCMD = "pwd ";

char *SPACMD;
  Pointer to command to display free disk space in current device/directory. 
  Example: char *SPACMD = "df .";

char *SPACM2;
  Pointer to command to display free disk space in another device/directory. 
  Example: char *SPACM2 = "df ";
  Note trailing space.  Device or directory name is added to this string.

char *TYPCMD;
  Pointer to command for displaying the contents of a file.
  Example: char *TYPCMD = "cat ";
  Note trailing space.  Device or directory name is added to this string.

char *WHOCMD;
  Pointer to command for displaying logged-in users.
  Example: char *WHOCMD = "who ";
  Note trailing space.  Specific user name may be added to this string.

int backgrd = 0;
  Flag for whether program is running in foreground (0) or background
  (nonzero).  Background operation implies that screen output should not be
  done and that all errors should be fatal.

int ckxech;
  Flag for who is to echo console typein:  
  1 - The program (system is not echoing).
  0 - The system, front end, terminal, etc (not this program)

char *ckxsys;
  Pointer to string that names the computer and operating system.
  Example: char *ckxsys = " NeXT Mach 1.0";
  Tells what computer system ckxv applies to.
  In UNIX Kermit, this variable is also used to print the program herald, 
  and in the SHOW VERSION command.

char *ckxv;
  Pointer to version/edit info of ck?tio.c module.
  Example: char *ckxv = "UNIX Communications Support, 6.0.169, 6 Sep 96";
  Used by SHOW VERSION command.

char *ckzsys;
  Like ckxsys, but briefer.
  Example: char *ckzsys = " 4.3 BSD";
  Tells what platform ckzv applies to.
  Used by the SHOW VERSION command.

char *ckzv;
  Pointer to version/edit info of ck?fio.c module.
  Example: char *ckzv = "UNIX File support, 6.0.113, 6 Sep 96";
  Used by SHOW VERSION command.

int dfflow;
  Default flow control.
  0 = none, 1 = Xon/Xoff, ... (see FLO_xxx symbols in ckcdeb.h)
  Set to by group 3 module.
  Used by ckcmai.c to initialize flow control variable.

int dfloc;
  Default location.
  0 = remote, 1 = local.
  Set by group 3 module.
  Used by ckcmai.c to initialize local variable.  Used in various places in
  the user interface.

int dfprty;
  Default parity.
  0 = none, 'e' = even, 'o' = odd, 'm' = mark, 's' = space.
  Set by Group 3 module.  Used by ckcmai.c to initialize parity variable.

char *dftty;
  Default communication device.
  Set by group 3 module.  Used in many places.
  This variable should be initialized the the symbol CTTNAM, which is defined
  in ckcdeb.h, e.g. as "/dev/tty" for UNIX, "TT:" for VAX/VMS, etc.
  Example: char *dftty = CTTNAM;

char *mtchs[];  *NEW*
  Array of string pointers to filenames that matched the most recent
  wildcard match, i.e. the most recent call to zxpand().  Used (at least) by
  command parsing package for partial filename completion.

int tilde_expand;  *NEW*
  Flag for whether to attempt to expand leading tildes in directory names
  (used in UNIX only, and then only when the symbol DTILDE is defined.

int ttnproto;  *NEW*
  The protocol being used to communicate over a network device.  Values are
  defined in ckcnet.h.  Example: NP_TELNET is network protocol "telnet".

int maxnam;  *NEW*
  The maximum length for a filename, exclusive of any device or directory
  information, in the format of the host operating system.

int maxpath;  *NEW*
  The maximum length for a fully specified filename, including device 
  designator, directory name, network node name, etc, in the format of
  the host operating system, and including all punctuation.

int ttyfd; *NEW*
  File descriptor of the communication device.  -1 if there is no open
  or usable connection, including when C-Kermit is in remote mode.
  Since this is not implemented everywhere, references to it are in
  #ifdef CK_TTYFD..#endif.

B. Functions.

These are divided into three categories: file-related functions (B.1),
communication functions (B.2), and miscellaneous functions (B.3).

B.1.  File-related functions.

In most implementations, these are collected together into a module called
CK?FIO.c, where ? = U (UNIX), V (VMS), O (OS/2), etc (see CKAAAA.HLP).  To be
totally system-independent, C-Kermit maintains its own file numbers, and
provides the functions described in this section to deal with the files
associated with them.  The file numbers are referred to symbolically, and are
defined as follows in CKCKER.H:

#define ZCTERM      0	    	/* Console terminal */
#define ZSTDIO      1		/* Standard input/output */
#define ZIFILE	    2		/* Current input file for SEND command */
#define ZOFILE      3	    	/* Current output file for RECEIVE command */
#define ZDFILE      4	    	/* Current debugging log file */
#define ZTFILE      5	    	/* Current transaction log file */
#define ZPFILE      6	    	/* Current packet log file */
#define ZSFILE      7		/* Current session log file */
#define ZSYSFN	    8		/* Input from a system function (pipe) */
#define ZRFILE      9           /* Local file for READ command */  (NEW)
#define ZWFILE     10           /* Local file for WRITE command */ (NEW)
#define ZMFILE     11           /* Auxilliary file for internal use */ (NEW)
#define ZNFILS     12	    	/* How many defined file numbers */

In the descriptions below, fn refers to a filename, and n refers to one of
these file numbers.  Functions are of type int unless otherwise noted, and are
listed alphabetically.

int
chkfn(n) int n;
  Checks the file number n.  Returns:
  -1: File number n is out of range
   0: n is in range, but file is not open
   1: n in range and file is open

int
iswild(filspec) char *filespec; *NEW*
  Checks if the file specification is "wild", i.e. contains metacharacters
  or other notations intended to match multiple filenames.  Returns:
   0: not wild
   1: wild

int
isdir(string) char *string; *NEW*
  Checks if the string is the name of an existing directory.  Returns:
   0: not a directory (including any kind of error)
   1: it is an existing directory
  The idea is to check whether the string can be "cd'd" to, so in some cases
  (e.g. OS/2) it might also indicate any file structured device, such as a
  disk drive (like A:).

char *
zfcdat(name) char *name; *NEW*
  Returns modification (preferably, otherwise creation) date/time of file
  whose name is given in the argument string.  Return value is a pointer to a
  string of the form yyyymmdd hh:mm:ss, for example 19931231 23:59:59, which
  represents the local time (no timezone or daylight savings time finagling
  required).  Returns the null string ("") on failure.  The text pointed to by
  the string pointer might be in a static buffer, and so should be copied to a
  safe place by the caller before any subsequent calls to this function.

struct zfnfp *
zfnqfp(fname, buflen, buf)  char * fname; int buflen; char * buf; *NEW*
  Given the filename "fname", the corresponding fully qualified, absolute
  filename is placed into the buffer buf, with maximum length buflen.
  On failure returns a NULL pointer.  On success returns a pointer to 
  a struct zfnfp (see ckcdeb.h) containing pointers to the full pathname
  and to just the filename.  All references to this function in mainline
  code must be protected by #ifdef ZFNQFP..#endif, because it is not present
  in all of the ck*fio.c modules.  So if you implement this function in a
  version that did not have it before, be sure to add #define ZFNQFP in the
  appropriate spot in ckcdeb.h.

int
zfseek(pos) long pos; *NEW*
  Positions the input pointer on the current input file to the given position.
  The pos argument is 0-based, the offset (distance in bytes) from beginning
  of the file.  Needed for RESEND, PSEND, and other recovery operations.  This
  function is not necessarily possible on all systems, e.g. record-oriented
  systems.  It should only be used on binary files (i.e. files we are sending
  in binary mode) and stream-oriented file systems.  Returns -1 on failure, 0
  on success.

int
zchdir(dirnam) char *dirnam;
  Change current or default directory to the one given in dirnam.
  Returns 1 on success, 0 on failure.

long
zchki(fn) char *fn;
  Check to see if file with name fn is a regular, readable, existing file,
  suitable for Kermit to send -- not a directory, not a symbolic link, etc.
  Returns:
  -3 if file exists but is not accessible (e.g. read-protected)
  -2 if file exists but is not of a readable type
  -1 on error (e.g. file does not exist, or fn is garbage)
  >= 0 (length of file) if file exists and is readable

int
zchko(fn) char *fn;
  Checks to see if a file of the given name can be created.  Returns:
  -1 if file cannot be created, or on any kind of error.
   0 if file can be created.

int
zchkspa(fn,len) char *f; long len;       *NEW*
  Check to see if there is sufficient space to store the file named fn,
  which is len bytes long.  Returns:
  -1 on error.
   0 if there is not enough space.
   1 if there is enough space.
  If you can't write a function to do this, then just make a dummy that
  always returns 1.  Higher level code will recover from disk-full errors.
  The receiving Kermit uses this function to refuse an incoming file based
  on its size, via the attribute mechanism.

int
zchin(n,c) int n; int *c;
  Get a character from file number n, return it in c (call with &c).
  Returns:
  -1 on failure, including EOF.
   0 on success with character in c.

int
zchout(n,c) int n; char c;
  Write the character c to file number n.  Returns:
  -1 error
   0 OK

int
zclose(n) int n;
  Close file number n.  Returns:
  -1 error
   1 OK

int
zdelet(fn) char *name;  *NEW*
  Attempts to delete the named file.  Returns:
  -1 on error
   0 if file was deleted successfully

char *
zgperm(char * f)  *NEW*
  Returns a pointer to the system-dependent permissions/protection string
  for file f, or NULL upon failure.  Used if CK_PERMS is defined.

char *
zgtdir()  *NEW*
  Returns a pointer to the name of the current directory, folder, etc, or a
  NULL pointer if the current directory cannot be determined.  If possible,
  the directory specification should be (a) fully specified, e.g. as a
  complete pathname, and (b) be suitable for appending a filename.  Thus, for
  example, UNIX directory names should end with '/'.  VMS directory names
  should look like DEV:[NAME] (rather than, say, NAME.DIR;1).

char *
zhome()
  Returns a pointer to a string containing the user's home directory, or NULL
  upon error.  Should be formatted like zgtdir() (q.v.).

int
zinfill()  *NEW*
  This function is used by the macro zminchar(), which is defined in ckcker.h.
  zminchar() manages its own buffer, and calls zinfill() to fill it whenever
  it becomes empty.  It is only used for sending files, and reads characters
  only from file number ZIFILE.  zinfill() returns -1 upon end of file,
  otherwise it returns the first character from the buffer it just read.

int
zkself()
  Kills the current job, session, process, etc, logs out, disappears.  Used by
  the Kermit server when it receives a BYE command.  On failure, returns -1.
  On success, does not return at all!  This function should not be called
  until all other steps have been taken to close files, etc.

VOID
zstrip(fn,&fn2) char *fn1, **fn2;
  Strip device and directory, etc, from file specification, leaving only the 
  filename.  For example DUA0:[PROGRAMS]OOFA.C;3 becomes OOFA.C, or
  /usr/fdc/oofa.c becomes oofa.c.  Returns pointer to result in fn2.

VOID
zltor(fn,fn2) char *fn1, *fn2;
  Local-To-Remote filename translation.  Translates the local filename fn into
  a format suitable for transmission to an arbitrary type of computer, and
  copies the result into the buffer pointed to by fn2.  Translation may involve
  (a) stripping the device and/or directory/path name, (b) converting
  lowercase to uppercase, (c) removing spaces and strange characters, or
  converting them to some innocuous alphabetic character like X, (d)
  discarding or converting extra periods (there should not be more than one).
  Does its best.  Returns no value.  name2 is a pointer to a buffer, furnished
  by the caller, into which zltor() writes the resulting name.  No length
  checking is done.

#ifdef NZLTOR
VOID
nzltor(fn,fn2,convert,pathnames,max) char *fn1,*fn2; int convert,pathnames,max;
  Replaces zltor.  This new version handles pathnames and checks length.  fn1
  and fn2 are as in zltor.  This version is called unconditionally for each
  file, rather than only when filename conversion is enabled.  Pathnames can
  have the following values:
    PATH_OFF: Pathname, if any, is to be stripped
    PATH_REL: The relative pathname is to be included
    PATH_ABS: The full pathname is to be included

  After handling pathnames, conversion is done to the result as in the zltor
  description if convert != 0; if relative or absolute pathnames are included,
  they are converted to UNIX format, i.e. with slash (/) as the directory
  separator.  The max parameter specifies the maximum size of fn2.
#endif /* NZLTOR */

int
zmail(addr,fn) char *addr, fn;  *NEW*
  Send the local, existing file fn as e-mail to the address addr.  Returns:
  Returns 0 on success
   2 if mail delivered but temp file can't be deleted
  -2 if mail can't be delivered

int
zmkdir(path) char *path;  *NEW*
  The path can be a file specification that might contain directory
  information, in which the filename is expected to be included, or an
  unambiguous directory specification (e.g. in UNIX it must end with "/").
  This routine attempts to create any directories in the given path
  that don't already exist.  Returns:
   0 or greater success: no directories needed creation,
     or else all directories that needed creation were created successfully;
     the return code is the number of directories that were created.
  -1 on failure to create any of the needed directories.

int
zrmdir(path) char *path;  *NEW*
  Attempts to remove the given directory.  Returns 0 on success, -1 on
  failure.  The detailed semantics are open -- should it fail if the directory
  contains any files or subdirectories, etc.  It is probably best for this
  routine to behave in whatever manner is customary on the underlying
  platform; e.g. in UNIX, VMS, DOS, etc, where directories can not be removed
  unless they are empty.

VOID
znewn(fn,s) char *fn, **s;
  Transforms the name fn into a filename which is guaranteed to be unique.
  If the file fn does not exist, then the new name will be the same as fn.
  Otherwise, it will be different.  Does its best, returns no value.  New
  name is created in caller's space.  Call like this: znewn(old,&new);.
  The second parameter is a pointer to the new name.  This pointer is set
  by znewn() to point to a static string in its own space.

int
znext(fn) char *fn;
  Copies the next file name from a file list created by zxpand() into the
  string pointed to by fn (see zxpand).  If no more files, then the null
  string is placed there.  Returns the number of files remaining in the list.
  NOTE: It might have been more useful if znext() returned a positive number
  when returning a filename and 0 when no files were left, but the definition
  can not be changed.  Thus, the true test of the success or failure of this
  function is to look in the buffer upon return, not to test the return code.

int
zopeni(n,fn) int n; char *fn;
  Opens the file named fn for input as file number n.  Returns:
  0 on failure.
  1 on success.

*NEW* (zopeno - the second two parameters are new)
int
zopeno(n,fn,zz,fcb) int n; char *name; struct zattr *zz; struct filinfo *fcb;
  Attempts to open the named file for output as file number n.  zz is a Kermit
  file attribute structure as defined in ckcdeb.h, containing various
  information about the file, including its size, creation date, and so forth.
  This function should attempt to honor as many of these as possible.  fcb is
  a "file control block" in the traditional sense, defined in ckcdeb.h,
  containing information of interest to complicated file systems like VAX/VMS,
  IBM MVS, etc, like blocksize, record length, organization, record format,
  carriage control, disposition (like create vs append), etc.  Returns:
  0 on failure.
  1 on success.

int
zoutdump()  *NEW*
  Dumps an output buffer.  Used with the macro zmchout() defined in ckcker.h.
  Used only with file number ZOFILE, i.e. the file that is being received by
  Kermit during file transfer.  Returns:
  -1 on failure.
   0 on success.

int
zprint(p,fn) char *p, *f;  *NEW*
  Prints the file with name fn on a local printer, with options p.  Returns:
  Returns 0 on success
   3 if file sent to printer but can't be deleted
  -3 if file can't be printed

int
zrename(fn,fn2) char *fn, *fn2;  *NEW*
  Changes the name of file fn to fn2.  If fn2 is the name of an existing
  directory, or a file-structured device, then file fn1 is moved to that
  directory or device, keeping its original name.  If fn2 lacks a directory
  separator when passed to this function, an appropriate one is supplied.

Returns:
  -1 on failure.
   0 on success.

int
zcopy(source,dest) char * source, * dest;  *NEW*
  Copies the source file(s) to the destination.  Returns:
  -1 on failure.
   0 on success.

VOID
zrtol(fn,fn2) char *fn, *fn2;
  Remote-To-Local filename translation.  Translates a "standard" filename
  (see zrtol) to a local filename.  For example, in Unix this function might
  convert an all-uppercase name to lowercase, but leave lower- or mix-case
  names alone.  Does its best, returns no value.  New name is in string
  pointed to by fn2.  No length checking is done.

#ifdef NZLTOR
nzrtol(fn,fn2,convert,pathnames,max) char *fn1,*fn2; int convert,pathnames,max;
  Replaces zrtol.  Like zrtol but handles pathnames and checks length.  See
  nzltor for detailed description of parameters.
#endif /* NZLTOR */

int
zsattr(xx) struct zattr *xx; {  *NEW*
  Fills in a Kermit file attribute structure for the file which is to be sent,
  namely the currently open ZIFILE.
  Returns:
  -1 on failure.
   0 on success with the structure filled in.
  If any string member is null, then it should be ignored by the caller.
  If any numeric member is -1, then it should be ignored by the caller.

int
zshcmd(s) char *s;
  s contains to pointer to a command to be executed by the host computer's
  shell, command parser, or operating system.  If the system allows the user
  to choose from a variety of command processors (shells), then this function
  should employ the user's preferred shell.  If possible, the user's job
  (environment, process, etc) should be set up to catch keyboard interruption
  signals to allow the user to halt the system command and return to Kermit.
  The command must run in ordinary, unprivileged user mode.
  If possible, this function should return -1 on failure to start the command,
  or else it should return 1 if the command succeeded and 0 if it failed.

int
zsyscmd(s) char *s;  *NEW*
  s contains to pointer to a command to be executed by the host computer's
  shell, command parser, or operating system.  If the system allows the user
  to choose from a variety of command processors (shells), then this function
  should employ the system standard shell (e.g. /bin/sh for Unix), so that the
  results will always be the same for everybody.  If possible, the user's job
  (environment, process, etc) should be set up to catch keyboard interruption
  signals to allow the user to halt the system command and return to Kermit.
  The command must run in ordinary, unprivileged user mode.
  If possible, this function should return -1 on failure to start the command,
  or else it should return 1 if the command succeeded and 0 if it failed.

int
zsinl(n,s,x) int n, x; char *s;  *NEW*
  Reads a line from file number n.
  Writes the line into the address s provided by the caller.
  Writing terminates when newline is read, but with newline discarded.
  Writing also terminates upon EOF or if length x is exhausted.
  Returns:
  -1 on EOF or error.
   0 on success.

int
zsout(n,s) int n; char *s;
  Writes the string s out to file number n.  Returns:
  -1 on failure.
   0 on success.

int
zsoutl(n,s) int n; char *s;
  Writes the string s out to file number n and adds a line (record) terminator 
  (boundary) appropriate for the system and the file format.
  Returns:
  -1 on failure.
   0 on success.

int
zsoutx(n,s,x) int n, x; char *s;
  Writes exactly x characters from string s to file number n.  If s has
  fewer than x characters, then the entire string s is written.  Returns:
  -1 on error.
  >= 0 on success, the number of characters actually written.

int
zstime(f,yy,x) char *f; struct zattr *yy; int x;  *NEW*
  Sets the creation date (and other attributes) of an existing file, or
  compares a file's creation date with a given date.  Call with:
  f  = pointer to name of existing file.
  yy = pointer to a Kermit file attribute structure in which yy->date.val
       is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00, which
       is to be used for setting or comparing the date.  Other attributes
       in the struct can also be set, such as the protection/permission
       (See Appendix I), when it makes sense (e.g. "yy->lprotect.val" can be
       set if the remote system ID matches the local one).
  x  = is a function code: 0 means to set the file's creation date as given.
       1 means compare the date from the yy struct with the file's date.
  Returns:
  -1 on any kind of error.
   0 if x is 0 and the file date was set successfully.
   0 if x is 1 and date from attribute structure > file creation date.
   1 if x is 1 and date from attribute structure <= file creation date.

VOID
zstrip(name,name2) char *name, **name2;  *NEW*
  Strips pathname from filename "name".  Constructs the resulting string
  in a static buffer in its own space and returns a pointer to it in name2.
  Also strips device name, file version numbers, and other "non-name" material.

*NEW* (zxcmd - arguments are new, writing to a command is new)

int
zxcmd(n,s) char *s;
  Runs a system command so its output can be accessed as if it were file n.
  The command is run in ordinary, unprivileged user mode.
  If n is ZSTDIO or ZCTERM, returns -1.
  If n is ZIFILE or ZRFILE, then Kermit reads from the command, otherwise
  Kermit writes to the command.  Returns 0 on error, 1 on success.

int
zxpand(fn) char *fn;
  Expands a wildcard string into an array of strings.  Returns the number of
  files that match fn1, with data structures set up so that first filename (if
  any) will be returned by the next znext() call.  If no files match, or if
  there is any kind of error, zxpand returns 0.  As of C-Kermit 6.0.193, there
  is a provision to have zxpand produce a list consisting only of directories:
  extern int dironly;.  If dironly is nonzero, then only directories should be
  put in the list.  This is to avoid having to change the API; implementations
  that do not know about the dironly flag will still work as before, and
  upper-level code may separate directories from regular files in the list by
  calling isdir() or zchki().  There is a similar flag to have it return
  regular files only: extern int fileonly.  If neither dironly nor fileonly is
  set, zxpand returns all files that match.  NOTE: It is essential that the
  number returned by zxpand() reflect the actual number of filenames that will
  be returned by znext calls().  In other words:
    for (i = zxpand(string); i > 0; i--) { znext(buf); printf("%s\n", buf); }
  should print all the file names; no more, no less.
  ANOTHER NOTE: In UNIX, DOS, OS-9, etc, where directories contain entries
  for themselves (.) and the superior directory (..), these should NOT be
  included in the list.

int
xsystem(cmd) char *cmd;
  Executes the system command without redirecting any of its i/o, similar
  (well, identical) to system() in Unix.  But before passing the command to
  the system, xsystem() ensures that all privileges are turned off, so that
  the system command will execute in ordinary unprivileged user mode.

B.1.5 Security/Privilege Functions (all *NEW*)

These functions are used by C-Kermit to adapt itself to operating systems
where the program can be made to run in a "privileged" mode.  C-Kermit
should NOT read and write files or start subprocesses as a privileged program.
This would present a serious threat to system security.  The security package
has been installed to prevent such security breaches by turning off the
program's special privileges at all times except when they are needed.

In UNIX, the only need Kermit has for privileged status is access to the UUCP
lockfile directory, in order to read, create, and destroy lockfiles, and to
open communication devices that are normally protected against the user.
Therefore, privileges should only be enabled for these operations and disabled
at all other times.  This relieves the programmer of the responsibility of
putting expensive and unreliable access checks around every file access and
subprocess creation.

Strictly speaking, these functions are not required in all C-Kermit
implementations, because their use (so far, at least) is internal to the group
3 modules.  However, they should be included in all C-Kermit implementations
for operating systems that support the notion of a privileged program (UNIX,
RSTS/E, what else?).

int
priv_ini()  *NEW*
  Determine whether the program is running in privileged status.  If so,
  turn off the privileges, in such a way that they can be turned on again
  when needed.  Called from sysinit() at program startup time.  Returns:
    0 on success
    nonzero on failure, in which case the program should halt immediately.

int
priv_on()  *NEW*
  If the program is not privileged, this function does nothing.  If the
  program is privileged, this function returns it to privileged status.
  priv_ini() must have been called first.  Returns:
    0 on success
    nonzero on failure

int
priv_off()  *NEW*
  Turns privileges off (if they are on) in such a way that they can be
  turned back on again.  Returns:
    0 on success
    nonzero on failure

int
priv_can()  *NEW*
  Turns privileges off in such a way that they cannot be turned back on.
  Returns:
    0 on success
    nonzero on failure

int
priv_chk()  *NEW*
  Attempts to turns privileges off in such a way that they can be turned on
  again later.  Then checks to make sure that they were really turned off.
  If they were not really turned off, then they are cancelled permanently.
  Returns:
    0 on success
    nonzero on failure

B.2.  Console-Related Functions.

These relate to the program's "console", or controlling terminal, i.e. the
terminal that the user is logged in on and types commands at, or on a PC or
workstation, the actual keyboard and screen.

int
conbin(esc) char esc;
  Puts the console into "binary" mode, so that Kermit's command parser can
  control echoing and other treatment of characters that the user types.
  esc is the character that will be used to get Kermit's attention during
  packet mode; puts this in a global place.  Sets the ckxech variable.
  Returns:
  -1 on error.
   0 on success.

int
concb(esc) char esc;
  Put console in "cbreak" (single-character wakeup) mode.  That is, ensure
  that each console character is available to the program immediately when the
  user types it.  Otherwise just like conbin().  Returns:
  -1 on error.
   0 on success.

int
conchk()
  Returns a number, 0 or greater, the number of characters waiting to be read
  from the console, i.e. the number of characters that the user has typed that
  have not been read yet.

long
congspd();   *NEW*
  Returns the speed ("baud rate") of the controlling terminal, if known,
  otherwise -1L.

int
congks(timo) int timo;   *NEW*
  Get Keyboard Scancode.  Reads a keyboard scan code from the physical console
  keyboard.  If the timo parameter is greater than zero, then times out and
  returns -2 if no character appears within the given number of seconds.  Upon
  any other kind of error, returns -1.  Upon success returns a scan code,
  which may be any positive integer.  For situations where scan codes cannot
  be read (for example, when an ASCII terminal is used as the job's
  controlling terminal), this function is identical to coninc(), i.e. it
  returns an 8-bit character value.  congks() is for use with workstations
  whose keyboards have Alternate, Command, Option, and similar modifier keys,
  and Function keys that generate codes greater than 255.

int
congm()
  Console get modes.  Gets the current console terminal modes and saves them 
  so that conres() can restore them later.  Returns 1 if it got the modes OK,
  0 if it did nothing (e.g. because Kermit is not connected with any terminal),
  -1 on error.

int
coninc(timo) int timo;
  Console Input Character.  Reads a character from the console.  If the timo
  parameter is greater than zero, then coninc() times out and returns -2 if no
  character appears within the given number of seconds.  Upon any other kind
  of error, returns -1.  Upon success, returns the character itself, with a
  value in the range 0-255 decimal.

VOID
conint(f,s) SIGTYP (*f)(), (*s)();  *NEW*
  Sets the console to generate an interrupt if the user types a keyboard
  interrupt character, and to transfer control the signal-handling function f.
  For systems with job control, s is the address of the function that suspends
  the job.  Sets the global variable "backgrd" to zero if Kermit is running in
  the foreground, and to nonzero if Kermit is running in the background.
  See ckcdeb.h for the definition of SIGTYP.  No return value.

VOID
connoi()
  Console no interrupts.  Disable keyboard interrupts on the console.
  No return value.

int
conoc(c) char c;
  Write character c to the console terminal.  Returns:
  0 on failure, 1 on success.

int
conol(s) char *s;
  Write string s to the console.  Returns -1 on error, 0 or greater on
  success.

int
conola(s) char *s[]; {
  Write an array of strings to the console.  Returns -1 on error, 0 or greater
  on success.

int
conoll(s) char *s;
  Write string s to the console, followed by the necessary line termination
  characters to put the console cursor at the beginning of the next line.
  Returns -1 on error, 0 or greater on success.

int
conres()
  Restore the console terminal to the modes obtained by congm().  Returns:
  -1 on error, 0 on success.

int
conxo(x,s) int x; char *s;
  Write x characters from string s to the console.  Returns 0 or greater on
  success, -1 on error.

char *
conkbg();  *NEW*
  Returns a pointer to the designator of the console keyboard type.
  For example, on a PC, this function would return "88", "101", etc.
  Upon failure, returns a pointer to the empty string.


B.3 - Communication Device Functions

The communication device is the device used for terminal emulation and file
transfer.  It may or may not be the same device as the console, and it may
or may not be a terminal device (it could also be a network device).  For
brevity, the communication device is referred to here as the "tty".  When the
communication device is the same as the console device, Kermit is said to be
in remote mode.  When the two devices are different, Kermit is in local mode.

int
ttchk()
  Returns the number of characters that have arrived at the communication
  device but have not yet been read by ttinc(), ttinl(), and friends.  If
  communication input is buffered (and it should be), this is the sum of the
  number of unread characters in Kermit's buffer PLUS the number of unread
  characters in the operating system's internal buffer.  The call must be
  nondestructive and nonblocking, and as inexpensive as possible.
  Returns:
   0 or greater on success,
   0 in case of internal error,
  -1 or less when it determines the  connection has been broken,
     or there is no connection.
  That is, a negative return from ttchk() should reliably indicate that there
  is no usable connection.  Furthermore, ttchk() should be callable at any
  time to see if the connection is open.  When the connection is open, every
  effort must be made to ensure that ttchk returns an accurate number of
  characters waiting to be read, rather than just 0 (no characters) or 1
  (1 or more characters), as would be the case when we use select().  This
  aspect of ttchk's operation is critical to successful operation of sliding
  windows and streaming, but "nondestructive buffer peeking" is an obscure
  operating system feature, and so when it is not available, we have to do it
  ourselves by managing our own internal buffer at a level below ttinc(),
  ttinl(), etc, as in the UNIX version (non-FIONREAD case).

int
ttclos()
  Closes the communication device (tty or network).  If there were any kind of
  exclusive access locks connected with the tty, these are released.  If the
  tty has a modem connection, it is hung up.  For true tty devices, the
  original tty device modes are restored.  Returns:
  -1 on failure.
   0 on success.

int
ttflui()
  Flush communications input buffer.  If any characters have arrived but have
  not yet been read, discard these characters.  If communications input is
  buffered by Kermit (and it should be), this function flushes Kermit's buffer
  as well as the operating system's internal input buffer.
  Returns:
  -1 on failure.
   0 on success.

int
ttfluo()  *NEW*
  Flush tty output buffer.  If any characters have been written but not
  actually transmitted (e.g. because the system has been flow-controlled),
  remove them from the system's output buffer.  (Note, this function is
  not actually used, but it is recommended that all C-Kermit programmers
  add it for future use, even if it is only a dummy function that returns 0
  always.)

int
ttgmdm()  *NEW*
  Looks for the modem signals CTS, DSR, and CTS, and returns those that are
  on in as its return value, in a bit mask as described for ttwmdm,
  in which a bit is on (1) or off (0) according to whether the corresponding
  signal is on (asserted) or off (not asserted).  Return values:
  -3 Not implemented
  -2 if the line does not have modem control
  -1 on error
  >= 0 on success, with bit mask containing the modem signals.

long
ttgspd()  *NEW*
  Returns the current tty speed in BITS (not CHARACTERS) per second, or -1
  if it is not known or if the tty is really a network, or upon any kind of
  error.  On success, the speed returned is the actual number of bits per
  second, like 1200, 9600, 19200, etc.

int
ttgwsiz()  *NEW*
  Get terminal window size.  Returns -1 on error, 0 if the window size can't
  be obtained, 1 if the window size has been successfully obtained.  Upon
  success, the external global variables tt_rows and tt_cols are set to the
  number of screen rows and number of screen columns, respectively.
  As this function is not implemented in all ck*tio.c modules, calls to it
  must be wrapped in #ifdef CK_TTGWSIZ..#endif.  NOTE: This function must
  be available to use the TELNET NAWS feature (Negotiate About Window Size)
  as well as Rlogin.

int
tthang()
  Hang up the current tty device.  For real tty devices, turn off DTR for
  about 1/3-1/2 second (or other length of time, depending on the system).
  If the tty is really a network connection, close it.  Returns:
  -1 on failure.
   0 if it does not even try to hang up.
   1 if it believes it hung up successfully.

VOID
ttimoff()  *NEW*
  Turns off all pending timer interrupts.

int
ttinc(timo) int timo;  *NEW* (function is old, return codes are new)
  Reads one character from the communication device.  If timo is greater than
  zero, wait the given number of seconds and then time out if no character
  arrives, otherwise wait forever for a character.  Returns:
  -3 internal error (e.g. tty modes set wrong)
  -2 communications disconnect
  -1 timeout or other error
  >= 0 the character that was read.
  It is HIGHLY RECOMMENDED that ttinc() be internally buffered so that calls
  to it are relatively inexpensive.  If it is possible to to implement ttinc()
  as a macro, all the better, for example something like:

  #define ttinc(t) ( (--txbufn >= 0) ? txbuf[ttbufp++] : txbufr(t) )

  (see description of txbufr() below)

*NEW* (ttinl - 5th arg, requirement not to destroy read-ahead characters)
int
ttinl(dest,max,timo,eol,start,turn)
 int max,timo,turn; CHAR *dest, eol, start;
  
  ttinl() is Kermit's packet reader.  Reads a packet from the communications
  device, or up to max characters, whichever occurs first.  A line is a string
  of characters starting with the start character up to and including the
  character given in eol or until the length is exhausted, or, if turn != 0,
  until the line turnaround character (turn) is read.  If turn is 0, ttinl()
  *should* use the packet length field to detect the end, to allow for the
  possibility that the eol character appears unprefixed in the packet data.
  (The turnaround character is for half-duplex linemode connections.)

  If timo is greater than zero, ttinl() times out if the eol character is not
  encountered within the given number of seconds and returns -1.

  The characters that were input are copied into "dest" with their parity bits
  stripped if parity is not none.  The first character copied into dest should
  be the start character, and the last should be the final character of the
  packet (the last block check character).  ttinl() should also absorb and
  discard the eol and turn characters, and any other characters that are
  waiting to be read, up until the next start character, so that subsequent
  calls to ttchk() will not succeed simply because there are some terminators
  still sitting in the buffer that ttinl() didn't read.  This operation, if
  performed, MUST NOT BLOCK (so if it can't be performed in a guaranteed
  nonblocking way, don't do it).

  On success, ttinl() returns the number of characters read.  Optionally,
  ttinl() can sense the parity of incoming packets.  If it does this, then it
  should set the global variable ttprty accordingly.  ttinl() should be coded
  to be as efficient as possible, since it is at the "inner loop" of packet
  reception.  ttinl() returns:

   -1 Timeout or other possibly correctable error.
   -2 Interrupted from keyboard.
   -3 Uncorrectable i/o error -- connection lost, configuration problem, etc.
   >= 0 on success, the number of characters that were actually read
        and placed in the dest buffer, not counting the trailing null.

int
ttoc(c) char c;
  Outputs the character c to the communication line.  If the operation fails
  to complete within two seconds, this function returns -1.  Otherwise it
  returns the number of characters actually written to the tty (0 or 1).  This
  function should only be used for interactive, character-mode operations, like
  terminal connection, script execution, dialer i/o, where the overhead of the
  signals and alarms does not create a bottleneck.  (THIS DESCRIPTION NEEDS
  IMPROVEMENT -- If the operation fails within a "certain amount of time"...
  which might be dependent on the communication method, speed, etc.  In
  particular, flow-control deadlocks must be accounted for and broken out of
  to prevent the program from hanging indefinitely, etc.)

int
ttol(s,n) int n; char *s;
  Kermit's packet writer.  Writes the n characters of the string pointed to
  to by s.  NOTE: It is ttol's responsibility to write ALL of the characters,
  not just some of them.  Returns:
  -1 on a possibly correctable error (so it can be retried).
  -3 on a fatal error, e.g. connection lost.
  >= 0 on success, the actual number of characters written (the specific
     number is not actually used for anything).

*NEW* (ttopen - negative value for modem = network, new timeout feature)
int
ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo;
  Opens a tty device, if it is not already open.  ttopen must check to make
  sure the SAME device is not already open; if it is, ttopen returns 
  successfully without doing anything.  If a DIFFERENT device is currently
  open, ttopen() must call ttclos() to close it before opening the new one.
Parameters:
    ttname: character string - device name or network host name.
    lcl:   If called with lcl < 0, sets value of lcl as follows:
      0: the terminal named by ttname is the job's controlling terminal.
      1: the terminal named by ttname is not the job's controlling terminal.
      If the line is already open, or if the requested line can't
      be opened, then lcl remains (and is returned as) -1.
    modem:
      Less than zero: this is the negative of the network type,
      and ttname is a network host name.  Network types (from ckcnet.h):
        NET_TCPB 1   TCP/IP Berkeley (socket)  (implemented in ckutio.c)
        NET_TCPA 2   TCP/IP AT&T (streams)     (not yet implemented)
        NET_DEC  3   DECnet                    (not yet implemented)
      Zero or greater: ttname is a terminal device name.    
      Zero means a direct connection (don't use modem signals).
      Positive means use modem signals depending on the current setting
      of ttcarr ( see ttscarr() ).
    timo:
      > 0: number of seconds to wait for open() to return before timing out.
      <=0: no timer, wait forever (e.g. for incoming call).
    For real tty devices, ttopen() attempts to gain exclusive access to the
    tty device, for example in UNIX by creating a "lockfile" (in other
    operating systems, like VMS, exclusive access probably requires no special
    action).
  Side effects:
    Copies its arguments and the tty file descriptor to global variables that
    are available to the other tty-related functions, with the lcl value
    altered as described above.   Gets all parameters and settings associated
    with the line and puts them in a global area, so that they can be restored
    by ttres(), e.g. when the device is closed.
  Returns:
    0 on success
   -5 if device is in use
   -4 if access to device is denied
   -3 if access to lock mechanism denied
   -2 upon timeout waiting for device to open
   -1 on other error

int
ttpkt(speed,flow,parity) long speed; int flow, parity;
  Puts the currently open tty device into the appropriate modes for
  transmitting Kermit packets.  The arguments are interpreted as follows:
  speed: if speed > -1, and the device is a true tty device, and Kermit is in
         local mode, ttpkt also sets the speed.
  flow:  if in the range 0-3, ttpkt selects the corresponding type of flow
         control.  Currently 0 is defined as no flow control, 1 is Xon/Xoff,
         and no other types are defined.  If (and this is a horrible hack, but
         it goes back many years and will be hard to eradicate) flow is 4,
         then the appropriate tty modes are set for modem dialing, a special
         case in which we talk to a modem-controlled line without requiring
         carrier.  If flow is 5, then we require carrier.
  parity:  This is simply copied into a global variable so that other
         functions (like ttinl, ttinc, etc) can use it.
  Side effects: Copies its arguments to global variables, flushes the terminal
         device input buffer.  
  Returns:
   -1 on error.
    0 on success.

int
ttsetflow(int)
  Enables the given type of flow control on the open serial communications
  device immediately.  Arguments are the FLO_xxx values from ckcdeb.h, except
  FLO_DIAL, FLO_DIAX, or FLO_AUTO, which are not actual flow-control types.
  Returns 0 on success, -1 on failure.  This definition added 6 Sep 96.

long *
ttspdlist() 6 Sep 1997
  Returns a pointer to an array of longs, or NULL on failure.  On success,
  element 0 of the array contains number, n, indicating how many follow.
  Elements 1-n are serial speeds, expressed in bits per second, that are legal
  on this platform.  The user interface may use this list to construct a menu,
  keyword table, etc.  As this is a new function, its use is protected by
  #ifdef TTSPDLIST..#endif.

int
ttres()
  Restores the tty device to the modes and settings that were in effect at
  the time it was opened (see ttopen).  Returns:
  -1 on error.
   0 on success.

int
ttruncmd(string) char * string; *NEW*
  Runs the given command on the local system, but redirects its input and
  output to the communication (SET LINE, SET PORT, or SET HOST) device.
  Returns 1 on success, 0 on failure.

int
ttscarr(carrier) int carrier;  *NEW*
  Copies its argument to a variable that is global to the other tty-related
  functions, and then returns it.  The values for carrier are defined in
  ckcdeb.h: CAR_ON, CAR_OFF, CAR_AUTO.  ttopen(), ttpkt(), and ttvt() use this
  variable when deciding how to open the tty device and what modes to select.
  The meanings are these:
  CAR_OFF:  Ignore carrier at all times.
  CAR_ON:   Require carrier at all times, except when dialing.
            This means, for example, that ttopen() could hang forever waiting 
            for carrier if it is not present.
  CAR_AUTO: If the modem type is zero (i.e. the connection is direct), this
            is the same as CAR_OFF.  If the modem type is positive, then heed
            carrier during CONNECT (ttvt mode), but ignore it at other times
            (packet mode, during SET LINE, etc).  Compatible with pre-5A
            versions of C-Kermit.  This should be the default carrier mode.
  Kermit's DIAL command ignores the carrier setting, but ttopen(), ttvt(), and
  ttpkt() all honor the carrier option in effect at the time they are called.
  None of this applies to remote mode (the tty device is the job's controlling
  terminal) or to network host connections (modem type is negative).

int
ttsndb()
  Send a BREAK signal on the tty device.  On a real tty device, send a real
  BREAK lasting approximately 275 milliseconds.  If this is not possible,
  simulate a BREAK by (for example) dropping down some very low baud rate,
  like 50, and sending a bunch of null characters.  On a network connection,
  do the appropriate network protocol for BREAK.  Returns:
  -1 on error.
   0 on success.

int
ttsndlb() *NEW*
  Like ttsndb(), but sends a "Long BREAK" (approx 1.5 seconds).
  For network connections, it is identical to ttsndb().
  Currently, this function is used only if CK_LBRK is defined (as it is
  for UNIX and VAX/VMS).

int
ttsspd(cps) int cps;  *NEW* (argument is now cps instead of bps)
  For real tty devices only, set the device transmission speed to (note
  carefully) TEN TIMES the argument.  The argument is in characters per
  second, but transmission speeds are in bits per second.  cps are used rather
  than bps because high speeds like 38400 are not expressible in a 16-bit int
  but longs cannot be used because keyword-table values are ints and not longs.
  If the argument is 7, then the bps is 75, not 70.  If the argument is 888,
  this is a special code for 75/1200 split-speed operation (75 bps out, 1200
  bps in).  Returns:
  -1 on error, meaning the requested speed is not valid or available.
  >= 0 on success (don't try to use this value for anything).

int
ttvt(speed,flow) long speed; int flow;
  Puts the currently open tty device into the appropriate modes for terminal
  emulation.  The arguments are interpreted as in ttpkt().  Side effects:
  ttvt() stores its arguments in global variables, and sets a flag that it has
  been called so that subsequent calls can be ignored so long as the arguments
  are the same as in the last effective call.  Other functions, such as
  ttopen(), ttclose(), ttres(), ttvt(), etc, that change the tty device in any
  way must unset this flag.  In UNIX Kermit, this flag is called tvtflg.

int
ttwmdm(mdmsig,timo) int mdmsig, timo;  *NEW*
  Waits up to timo seconds for all of the given modem signals to appear.
  mdmsig is a bit mask, in which a bit is on (1) or off (0) according to
  whether the corresponding signal is to be waited for.  These symbols are
  defined in ckcdeb.h:
     BM_CTS (bit 0) means wait for Clear To Send 
     BM_DSR (bit 1) means wait for Data Set Ready
     BM_DCD (bit 2) means wait for Carrier Detect
  Returns:
    -3 Not implemented.
    -2 This line does not have modem control.
    -1 Timeout: time limit exceeded before all signals were detected.
     1 Success.

int
ttxin(n,buf) int n; CHAR *buf;
  (note: CHAR is used throughout this program, and should be typedef'd to
  unsigned char if your C compiler supports it.  See ckcdeb.h.)
  Read x characters from the tty device into the specified buf, stripping
  parity if parity is not none.  This call waits forever, there is no timeout.
  This function is designed to be called only when you know that at least x
  characters are waiting to be read (as determined, for example, by ttchk()). 
  This function should use the same buffer as ttinc().

int
txbufr(timo) int timo; *NEW*
  Read characters into the interal communications input buffer.  timo is a
  timeout interval, in seconds.  0 means no timeout, wait forever.  Called by
  ttinc() (and possibly ttxin() and ttinl()) when the communications input
  buffer is empty.  The buffer should be called ttxbuf[], its length is
  defined by the symbol TXBUFL.  The global variable txbufn is the number of
  characters available to be read from ttxbuf[], and txbufp is the index of
  the next character to be read.  Should not be called if txbufn > 0, in which
  case the buffer does not need refilling.  This routine returns:
   -2    Communications disconnect
   -1    Timeout
   >= 0  A character (0 - 255), the first character that was read, with
         the variables txbufn and txbufp set appropriately for any remaining
         characters.
  NOTE: Currently this routine is used internally only by the UNIX and VMS
  versions.  The aim is to make it available to all versions so there is one
  single coherent and efficient way of reading from the communications device
  or network.

B.4 - Miscellaneous system-dependent functions.

VOID
ztime(s) char **s;

  Return a pointer, s, to the current date-and-time string in s.  This string
  must be in the fixed-field format associated with the C language
  "asctime()" function, like: "Sun Sep 16 13:23:45 1973\n" so that callers of
  this function can extract the different fields.  The pointer value is filled
  in by ztime, and the data it points to is not safe, so should be copied to
  a safe place before use.  ztime() has no return value.
    
int
gtimer()
  Returns the current value of the elapsed time counter in seconds (see
  rtimer), or 0 on any kind of error.

#ifdef GFTIMER
float
gtimer()
  Returns the current value of the elapsed time counter in seconds, as
  a floating point number, capable of representing not only whole seconds,
  but also the fractional part, to the millisecond or microsecond level,
  whatever precision is available.  Requires a function to get times at
  subsecond precision, as well as floating-point support.  That's why it's
  #ifdef'd.
#endif /* GFTIMER */

int
msleep(m) int m;
  Sleeps (pauses, does nothing) for m milliseconds (a millisecond is one
  thousandth of a second).  Returns:
  -1 on failure.
   0 on success.

VOID
rtimer()
  Sets the elapsed time counter to zero.  If you want to time how long an
  operation takes, call rtimer() when it starts and gtimer when it ends.
  rtimer() has no return value.

#ifdef GFTIMER
VOID
rftimer()
  Sets the elapsed time counter to zero.  If you want to time how long an
  operation takes, call rftimer() when it starts and gftimer when it ends.
  rftimer() has no return value.  Note: rftimer() is to be used with gftimer()
  and rtimer() is to be used with gtimer().  See rftimer() description.
#endif /* GFTIMER */

int
sysinit()
  Does whatever needs doing upon program start.  In particular, if the
  program is running in any kind of privileged mode, turns off the privileges
  (see priv_ini()).  Returns:
  -1 on error.
   0 on success.

int
syscleanup()
  Does whatever needs doing upon program exit.  Returns:
  -1 on error.
   0 on success.

int
psuspend()   *NEW*
  Suspends the Kermit process, puts it in the background so it can be
  continued ("foregrounded") later.  Returns:
  -1 if this function is not supported.
   0 on success.

GROUP 4 - Network Support.

As of version 5A, C-Kermit includes support for several networks.  Originally,
this was just worked into the ttopen(), ttclos(), ttinc(), ttinl(), and
similar routines in CKUTIO.C.  However, this made it impossible to share this
code with non-UNIX versions, like VMS.

As of edit 168, this support has been separated out into its own module and
header file, CKCNET.C and CKCNET.H.  The routines and variables in this module
fall into two categories: (1) support for specific network packages like
SunLink X.25 and TGV MultiNet, and (2) support for specific network virtual
terminal protocols like CCITT X.3 and TCP/IP telnet.  Category (1) functions
are analogs to the tt*() functions, and have names like netopen, netclos,
nettinc, etc.  Group I and II modules do not (and must not) know anything
about these functions -- they continue to call the old Group III functions
(ttopen, ttinc, etc).  Category (2) functions are protocol specific and have
names prefixed by a protocol identifier, like tn for telnet x25 for X.25.

CKCNET.H contains prototypes for all these functions, as well as symbol
definitions for network types, protocols, and network- and protocol- specific
symbols, as well as #includes for the header files necessary for each network
and protocol.

The following functions are to be provided for networks that do not use normal
system i/o (open, read, write, close):

int
netopen()
  To be called from within ttopen() when a network connection is requested.
  Calling conventions and purpose same as Group III ttopen().

int
netclos()
  To be called from within ttclos() when a network connection is being closed.
  Calling conventions and purpose same as Group III ttclos().

int
nettchk()
  To be called from within ttchk().
  Calling conventions and purpose same as Group III ttchk().

int
netflui()
  To be called from within ttflui().
  Calling conventions and purpose same as Group III ttflui().

int
netbreak()
  To send a network break (attention) signal.
  Calling conventions and purpose same as Group III ttsndbrk().

int
netinc()
  To get a character from the network.
  Calling conventions same as Group III ttsndbrk().

int
nettoc()
  Send a "character" (byte) to the network.
  Calling conventions same as Group III ttoc().

int
nettol()
  Send a "line" (sequence of bytes) to the network.
  Calling conventions same as Group III ttol().

Conceivably, some systems support network connections simply by letting
you open a device of a certain name and letting you do i/o to it.  Others
(like the Berkeley sockets TCP/IP library on UNIX) require you to open the
connection in a special way, but then do normal i/o (read, write).  In such
a case, you would use netopen(), but you would not use nettinc, nettoc, etc.

TGV MultiNET on VAX/VMS has its own set of functions for all network
operations, so in that case the full range of netxxx() functions is used.

The technique is to put a test in each corresponding ttxxx() function to
see if a network connection is active (or is being requested), test for which
kind of network it is, and if necessary route the call to the corresponding
netxxx() function.  The netxxx() function must also contain code to test for
the network type, which is available via the global variable ttnet.

TELNET SUPPORT:

The telnet protocol is supported by the following variables and routines:

(global) int tn_init: nonzero if telnet protocol initialized, zero otherwise.

int
tn_init()
  Initialize the telnet protocol (send initial options).

int
tn_sopt()
  Send a telnet option.

int
tn_doop()
  Receive and act on a telnet option from the remote.

int
tn_sttyp()
  Send terminal type using telnet protocol.

X.25 SUPPORT:

These are presently specific to SunLink X.25, but it is hoped that they can
be integrated better with the functions above, and made more general so they
could be used, for instance, with VAX PSI.

x25diag()
  Read and print X.25 diagnostic

x25oobh()
  X.25 out of band signal handler

x25intr()
  Send X.25 interrupt packet

x25reset()
  Reset X.25 virtual circuit

x25clear()
  Clear X.25 virtual circuit

x25stat()
  X.25 status

setqbit()
  Set X.25 Q-bit

resetqbit()
  Reset X.25 Q-bit

x25xin()
  Read n characters from X.25 circuit.

x25inl()
  Read a Kermit packet from X.25 circuit.

ADDING SUPPORT FOR A NEW NETWORK TYPE

Example: Adding support for IBM X.25 and Hewlett Packard X.25.
First, add new network type symbols for each one.  There are already
some network types defined for other X.25 packages:

  NET_SX25 is the network-type ID for SunLink X.25.
  NET_VX25 is the network-type ID for VOS X.25.

So first you should new symbols for the new network types, giving them
the next numbers in the sequence, e.g.:

#define NET_HX25 11			/* Hewlett-Packard X.25 */
#define NET_IX25 12			/* IBM X.25 */

This is in ckcnet.h.

Then we need symbols to say that we are actually compiling in the code
for these platforms.  These would be defined on the cc command line:

  -DIBMX25  (for IBM)
  -DHPX25   (for HP)

So we can build C-Kermit versions for AIX and HP-UX both with and without
X.25 support (since not all AIX and IBM systems have the needed libraries,
and so an executable that was linked with them might no load).

Then in ckcnet.h:

#ifdef IBMX25
#define ANYX25
#endif /* IBMX25 */

#ifdef HPX25
#define ANYX25
#endif /* HPX25 */

And then use ANYX25 for code that is common to all of them,
and IBMX25 or HPX25 for code specific to IBM or HP.

It might also happen that some code can be shared between two or more of
these, but not the others.  Suppose, for example, that you write code that
applies to both IBM and HP, but not Sun or VOS X.25.  Then you add the
following definition to ckcnet.h:

#ifndef HPORIBMX25
#ifdef HPX25
#define HPORIBMX25
#else
#ifdef IBMX25
#define HPORIBMX25
#endif /* IBMX25 */
#endif /* HPX25 */
#endif /* HPORIBMX25 */

You can NOT use constructions like "#if defined (HPX25 || IBMX25)"; they
are not portable (see ckcplm.doc).

GROUP 5 - Formatted Screen Support

So far, this is used only for the fullscreen local-mode file transfer display.
In the future, it might be extended to other uses.  The fullscreen display
code is in and around the routine screenc() in ckuusx.c.

In the UNIX version, we use the curses library, plus one call from the termcap
library.  In other versions (OS/2, VMS, etc) we insert dummy routines that
have the same names as curses routines.  So far, there are two methods for
simulating curses routines:

 1. In VMS, we use the Screen Management Library (SMG), and insert stubs
    to convert curses calls into SMG calls.

 2. In OS/2, we use the MYCURSES code, in which the stub routines
    actually emit the appropriate escape sequences themselves.

Here are the stub routines:

tgetent(char *buf, char *term)
  Arguments are ignored.  Returns 1 if the user has a supported terminal
  type, 0 otherwise.  Sets a global variable (for example, "isvt52" or
  "isdasher") to indicate the terminal type.

move(int row, int col)
  Sends the escape sequence to position the cursor at the indicated row
  and column.  The numbers are 0-based, e.g. the home position is 0,0.

clear()
  Sends the escape sequence to clear the screen.

clrtoeol()
  Sends the escape sequence to clear from the current cursor position to
  the end of the line.

In the MYCURSES case, code must be added to each of the last three routines
to emit the appropriate escape sequences for a new terminal type.

clearok(curscr), wrefresh()
  In real curses, these two calls are required to refresh the screen, for
  example after it was fractured by a broadcast message.  These are useful
  only if the underlying screen management service keeps a copy of the entire
  screen, as curses and SMG do.  C-Kermit does not do this itself.

APPENDIX I - File Permissions

I.1. Format of System-Dependent File Permissions in A-Packets

The format of this field (the "," attribute) is interpreted according to the
System ID ("." Attribute).

For UNIX (System ID = U1), it's the familiar 3-digit octal number, the
low-order 9 bits of the filemode: Owner, Group, World, e.g. 660 = read/write
access for owner and group, none for world, recorded as a 3-digit octal string.

For VMS (System ID = D7), it's a 4-digit hex string, representing the 16-bit
file protection WGOS fields (World,Group,Owner,System), in that order (which
is the reverse of how they're shown in a directory listing); in each field,
Bit 0 = Read, 1 = Write, 2 = Execute, 3 = Delete.  A bit value of 0 means
permission is granted, 1 means permission is denied.  Sample:

  r-01-00-^A/!FWERMIT.EXE'" 
  s-01-00-^AE!Y/amd/watsun/w/fdc/new/wermit.exe.DV
  r-02-01-^A]"A."D7""B8#119980101 18:14:05!#8531&872960,$A20B-!7(#512@ #.Y
  s-02-01-^A%"Y.5!                                     ^^^^^^

A VMS directory listing shows the file's protection as (E,RWED,RED,RE) which
really means (S=E,O=RWED,G=RED,W=RE), which is reverse order from the internal
storage, so (RE,RED,RWED,E).  Now translate each letter to its corresponding
bit:

  RE=0101, RED=1101, RWED=1111, E=0010

Now reverse the bits:

  RE=1010, RED=0010, RWED=0000, E=1101

This gives the 16-bit quantity: 

  1010001000001101

This is the internal representation of the VMS file permission; in hex:

  A20B

as shown in the sample packet above.

The VMS format probably would also apply to RSX or any other FILES-11 system.

I.2. Handling of Generic Protection

To be used when the two systems are different (and/or do not recognize or
understand each other's local protection codes).

First of all, the book is wrong.  This should not be the World protection, 
but the Owner protection.  The other fields should be set according to system
defaults (e.g. UNIX umask, VMS default protection, etc), except that no
non-Owner field should give more permissions than the Owner field.

(End of CKCPLM.DOC)