File: ckcplm.txt

package info (click to toggle)
ckermit 211-5
  • links: PTS
  • area: non-free
  • in suites: sarge
  • size: 11,700 kB
  • ctags: 14,540
  • sloc: ansic: 239,818; makefile: 4,582; sh: 51
file content (3076 lines) | stat: -rw-r--r-- 137,538 bytes parent folder | download | duplicates (4)
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
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076

                         C-Kermit Program Logic Manual

     Frank da Cruz
     [1]The Kermit Project
     [2]Columbia University

   As of: C-Kermit 8.0.211, 10 April 2004
   This page last updated: Sat Apr 10 16:45:30 2004 (New York USA Time)

     IF YOU ARE READING A PLAIN-TEXT version of this document, note that
     this file is a plain-text dump of a Web page. You can visit the
     original (and possibly more up-to-date) Web page here:

  [3]http://www.columbia.edu/kermit/ckcplm.html

   [ [4]C-Kermit Home ] [ [5]Kermit Home ]
    ________________________________________________________________________

  CONTENTS

  1. [6]INTRODUCTION
  2. [7]FILES
  3. [8]SOURCE CODE PORTABILITY AND STYLE
  4. [9]MODULES
     4.A. [10]Group A: Library Routines
     4.B. [11]Group B: Kermit File Transfer
     4.C. [12]Group C: Character-Set Conversion
     4.D. [13]Group D: User Interface
     4.E. [14]Group E: Platform-Dependent I/O
     4.F. [15]Group F: Network Support
     4.G. [16]Group G: Formatted Screen Support
     4.H. [17]Group H: Pseudoterminal Support
     4.I. [18]Group I: Security
  I. [19]APPENDIX I: FILE PERMISSIONS
    ________________________________________________________________________

  1. 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 describes the relationship among the modules and functions
   of C-Kermit 5A and later, and other programming considerations.
   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, as shown in the [20]Contents.

   C-Kermit has seen constant development since 1985. Throughout its
   history, there has been a neverending tug-of-war among:

    a. Functionality: adding new features, fixing bugs, improving
       performance.
    b. Adding support for new platforms.
    c. "Buzzword 1.0 compliance".

   The latter category is the most frustrating, since it generally
   involves massive changes just to keep the software doing what it did
   before in some new setting: e.g. the K&R-to-ANSIC conversion (which
   had to be done, of course, without breaking K&R); Y2K (not a big deal
   in our case); the many and varied UNIX and other API "standards";
   IPv6.

   [ [21]Contents ] [ [22]C-Kermit ] [ [23]Kermit Home ]
    ________________________________________________________________________

  2. FILES

   C-Kermit source files begin with the two letters "ck", for example
   ckutio.c. Filenames are kept short (6.3) for maximum portability and
   (obviously I hope) do not contain spaces or more than one period. The
   third character in the name denotes something about the function group
   and the expected level of portability:

     a     General descriptive material and documentation (text)
     b     BOO file encoders and decoders (obsolete)
     c     All platforms with C compilers (*)
     d     Data General AOS/VS
     e     Reserved for "ckermit" files, like ckermit.ini, ckermit2.txt
     f     (reserved)
     g     (reserved)
     h     (reserved)
     i     Commodore Amiga (Intuition)
     j     (unused)
     k     (unused)
     l     Stratus VOS
     m     Macintosh with Mac OS 1-9
     n     Microsoft Windows NT/2000/XP
     o     OS/2 and/or Microsoft Windows 9x/ME/NT/2000/XP
     p     Plan 9 from Bell Labs
     q     (reserved)
     r     DEC PDP-11 with RSTS/E (never used, open for reassigment)
     s     Atari ST GEMDOS (last supported in version 5A(189))
     t     DEC PDP-11 with RT-11 (never used, open for reassigment)
     u     Unix-based operating systems (*)
     v     VMS and OpenVMS
     w     Wart (Lex-like preprocessor, platform independent)
     x     (reserved)
     y     (reserved)
     z     (reserved)
     0-3   (reserved)
     4     IBM AS/400
     5-8   (reserved)
     9     Microware OS-9
     _     Encryption modules

   (*) In fact there is little distinction between the ckc*.* and cku*.*
   categories. It would make more sense for all cku*.* modules to be
   ckc*.* ones, except ckufio.c, ckutio.c, ckucon.c, ckucns.c, and
   ckupty.c, which truly are specific to Unix. The rest (ckuus*.c,
   ckucmd.c, etc) are quite portable.

   One hint before proceeding: functions are scattered all over the
   ckc*.c and cku*.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 in
   what source file a given function is defined 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 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 the opening bracket is above the visible screen, and it also
   makes it easy to find the end of a function (search for '}' on the
   left margin).

   Of course EMACS tags work nicely with this format too:

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

   (but remember that the source file for ckcpro.c is [24]ckcpro.w!)

   Also:

     * 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 (obviously this is not a portability issue, just
       style).

   [ [25]Contents ] [ [26]C-Kermit ] [ [27]Kermit Home ]
    ________________________________________________________________________

  3. SOURCE CODE PORTABILITY AND STYLE

   C-Kermit was designed in 1985 as a platform-independent replacement
   for the earlier Unix Kermit. c-Kermit's design was expected to promote
   portability, and judging from the number of platforms to which it has
   been adapted since then, the model is effective, if not ideal
   (obviously if we had it all to do over, we'd change a few things). To
   answer the oft-repeated question: "Why are there so many #ifdefs?",
   it's because:

     * Many of them are related to feature selection and program size,
       and so need to be there anyway.
     * Those that treat compiler, library, platform, header-file, and
       similar differences have built up over time as hundreds of people
       all over the world adapted C-Kermit to their particular
       environments and sent back their changes. There might be more
       politically-correct ways to achieve portability, but this one is
       natural and proven. The basic idea is to introduce changes that
       can be selected by defining a symbol, which, if not defined,
       leaves the program exactly as it was before the changes.
     * Although it might be possible to "clean up" the "#ifdef mess",
       nobody has access to all the hundreds of platforms served by the
       #ifdefs to check the results.

   And to answer the second-most-oft-repeated question: "Why don't you
   just use GNU autoconfig / automake / autowhatever instead of
   hard-coding all those #ifdefs?" Answers:

     * The GNU tools are not available on all the platforms where
       C-Kermit must be built and I wouldn't necessarily trust them if
       they were.
     * Each platform is a moving target, so the tools themselves would
       need to updated before Kermit could be updated.
     * It would only add another layer of complexity to an already
       complex process.
     * Conversion at this point would not be practical unless there was a
       way to test the results on all the hundreds of platforms where
       C-Kermit is supposed to build.

   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. The same holds true
   for many of the "system dependent" modules too; particularly the Unix
   ones, since they must be buildable by a wide variety of compilers and
   linkers, new and old.

   This list does not purport to be comprehensive, and although some
   items on it might seem far-fetched, they would not be listed unless I
   had encountered them somewhere, some time. I wish I had kept better
   records so I could cite specific platforms and compilers.

     * 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 old linkers (actually, this goes back to
       TOPS-10 and -20 and other old DEC OS's where C-Kermit never ran
       anyway; a more realistic maximum is probably somewhere between 8
       and 16). We know for certain that VAX C has a 31-character max
       because it complains -- others might not complain, but just
       silently truncate, thus folding two or more routines/variables
       into one.
     * Keep preprocessor symbols unique within 8 characters; that's the
       max for some preprocessors (sorry, I can't give a specific
       example, but in 1988 or thereabouts, I had to change character-set
       symbols like TC_LATIN1 and TC_LATIN2 to TC_1LATIN and TC_2LATIN
       because the digits were being truncated and ignored on a platform
       where I actually had to build C-Kermit 5A; unfortunately I didn't
       note which platform -- maybe some early Ultrix version?)
     * Don't create preprocessor symbols, or variable or function names,
       that start with underscore (_). These are usually reserved for
       internal use by the compiler and header files.
     * Don't put #include directives inside functions or { blocks }.
     * Don't use the #if or #elif preprocessor constructions, only use
       #ifdef, #ifndef, #define, #undef, and #endif.
     * 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.
     * Avoid #ifdefs inside argument list to function calls (I can't
       remember why this one is here, but probably needn't be; we do this
       all the time).
     * 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.
     * Avoid typedefs; they might be portable but they are very confusing
       and there's no way to test for their presence or absence at
       compile time. Use preprocessor symbols instead if possible; at
       least you can test their definitions.
     * Unsigned long is not portable; use a preprocessor symbol (Kermit
       uses ULONG for this).
     * Long long is not portable. If you really need it, be creative.
     * Similarly 1234LL is not portable, nor almost any other constant
       modifier other than L.
     * Unsigned char is not portable, use CHAR (a preprocessor symbol
       defined in the Kermit header files) and always take precautions
       against character signage (more about this [28]below).
     * Don't use initializers with automatic arrays or structs: it's not
       portable.
     * Don't use big automatic arrays or structs in functions that might
       be called recursively; some platforms have fixed-size stacks (e.g.
       Windows 9x: 256K) and recursive functions crash with stack
       overflow. Even when there is not a compiler limitation, this
       causes memory to be consumed without bound, and can end up filling
       swap space.
     * Don't assume that struct assignment performs a copy, or that it
       even exists.
     * Don't use sizeof to get the size of an array; someone might come
       along later and and change it from static to malloc'd. Always use
       a symbol to refer to the array's size.
     * Don't put prototypes for static functions into header files that
       are used by modules that don't contain that function; the link
       step can fail with unresolved references (e.g. on AOS/VS).
     * Avoid the construction *++p (the order of evaluation varies; it
       shouldn't but at least one compiler had a bug that made me include
       this item).
     * Don't use triple assignments, like a = b = c = 0; (or quadruple,
       etc). Some compilers generate bad code for these, or crash, etc
       (some version of DEC C as I recall).
     * Some compilers don't allow structure members to have the same
       names as other identifiers. Try to give structure members unique
       names.
     * Don't assume anything about order of evaluation in boolean
       expressions, or that they will stop early if a required condition
       is not true, e.g.:
  if (i > 0 && p[i-1] == blah)
       can still dump core if i == 0 (hopefully this is not true of any
       modern compiler, but I would not have said this if it did not
       actually happen somewhere).
     * Don't have a switch() statement with no cases (e.g. because of
       #ifdefs); this is a fatal error in some compilers.
     * Don't put lots of code in a switch case; move it out to a separate
       function; some compilers run out of memory when presented with a
       huge switch() statement -- it's not the number of cases that
       matters; it's the overall amount of code.
     * Some compilers might also limit the number of switch() cases, e.g.
       to 254.
     * Don't put anything between "switch() {" and "case:" -- switch
       blocks are not like other blocks.
     * Don't jump into or out of switches.
     * Don't make character-string constants longer than about 250 bytes.
       Longer strings should be broken up into arrays of strings.
     * Don't write into character-string constants (obviously). Even when
       you know you are not writing past the end; 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. as separate
       switch() cases).
     * 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, pid_t, etc), except
       time_t, without #ifdef protection (time_t is the only one I've
       found that is accepted everywhere). This is a tough one because
       the same function might require (say) a size_t arg on one
       platform, whereas size_t is unheard of on another; or worse, it
       might require a totally different data type, like int or long or
       some other typedef'd thing. It has often proved necessary to
       define a symbol to stand for the type of a particular argument to
       a particular library or system function to get around this
       problem.
     * 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. Kermit does all character-set
       conversion itself and does not use any external libraries or
       functions.
     * In particular, don't use any library functions that deal with wide
       characters or Unicode in any form. These are not only nonportable,
       but a constantly shifting target (e.g. the ones in glibc).
     * 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 differences 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 if you can).
     * On the other hand, don't assume that signals are disarmed after
       being raised. In some platforms you have to re-arm them, in others
       they stay armed.
     * Don't call malloc() and friends from a signal handler; don't do
       anything but setting integer global variables in a signal handler.
     * malloc() does not initialize allocated memory -- it never said it
       did. Don't expect it to be all 0's.
     * Did You Know: malloc() can succeed and the program can still dump
       core later when it attempts to use the malloc'd memory? (This
       happens when allocation is deferred until use and swap space is
       full.)
     * memset(), memmove(), and memcpy() are not portable, don't use them
       without protecting them in ifdefs (we have USE_MEMCPY for this).
       bzero()/bcopy() too, except we're guaranteed to have
       bzero()/bcopy() when using the sockets library (not really). See
       examples in the source.
     * Don't assume that strncpy() stops on the first null byte -- most
       versions always copy the number of bytes given in arg 3, padding
       out with 0's and overwriting whatever was there before. Use
       C-Kermit ckstrncpy() if you want predictable non-padding behavior,
       guaranteed NUL-termination, and a useful return code.
     * 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 ntohs() or whatever 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.
     * Use the Kermit _PROTOTYP() macro for declaring function
       prototypes; it works in both the ANSI and non-ANSI cases.
     * 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 use // as a comment introducer. C is not C++.
     * Don't declare a string as "char foo[]" in one module and "extern
       char * foo" in another, or vice-versa: this causes core dumps.
     * With compiler makers falling all over themselves trying to outdo
       each other in ANSI strictness, it has become increasingly
       necessary to cast EVERYTHING. This is increasingly true for char
       vs unsigned char. We need to use unsigned chars if we want to deal
       with 8-bit character sets, but most character- and string-oriented
       APIs want (signed) char arguments, so explicit casts are
       necessary. It would be nice if every compiler had a
       -funsigned-char option (as gcc does), but they don't.
     * 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: 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.
     * At least one compiler (the one on DEC OSF/1 1.3) treats "/*" and
       "*/" within string constants as comment begin and end. No amount
       of #ifdefs will get around this one. You simply can't put these
       sequences in a string constant, e.g. "/usr/local/doc/*.*".
     * Avoid putting multiple macro references on a single line, e.g.:
  putchar(BS); putchar(SP); putchar(BS)

   This overflows the CPP output buffer of more than a few C
   preprocessors (this happened, for example, with SunOS 4.1 cc, which
   evidently has a 1K macro expansion buffer).

   C-Kermit needs constant adjustment to new OS and compiler releases.
   Every new OS 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 conservative when
   attempting to write portable code. Avoid all advanced features.

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

   But finally... feel free to violate any or all of these rules in
   platform-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, because VAX C, DEC C, and VMS GCC all support it.

   [ [29]Contents ] [ [30]C-Kermit ] [ [31]Kermit Home ]
    ________________________________________________________________________

  3.1. Memory Leaks

   The C language and standard C library are notoriously inadequate and
   unsafe. Strings are arrays of characters, usually referenced through
   pointers. There is no native string datatype. Buffers are fixed size,
   and C provides no runtime bounds checking, thus allowing overwriting
   of other data or even program code. With the popularization of the
   Internet, the "buffer exploit" has become a preferred method for
   hackers to hijack privileged programs; long data strings are fed to a
   program in hopes that it uses unsafe C library calls such as strcpy()
   or sprintf() to copy strings into automatic arrays, thus overwriting
   the call stack, and therefore the routine's return address. When such
   a hole is discovered, a "string" can be constructed that contains
   machine code to hijack the program's privileges and penetrate the
   system.

   This problem is partially addressed by the strn...() routines, which
   should always be used in preference to their str...() equivalents
   (except when the copy operation has already been prechecked, or there
   is a good reason for not using them, e.g. the sometimes undesirable
   side effect of strncpy() zeroing the remainder of the buffer). The
   most gaping whole, however, is sprintf(), which performs no length
   checking on its destination buffer, and is not easy to replace.
   Although snprintf() routines are starting to appear, they are not yet
   widespread, and certainly not universal, nor are they especially
   portable, or even full-featured.

   For these reasons, we have started to build up our own little library
   of C Library replacements, ckclib.[ch]. These are safe and highly
   portable primitives for memory management and string manipulation,
   such as:

   ckstrncpy()
          Like strncpy but returns a useful value, doesn't zero buffer.

   ckitoa()
          Opposite of atoi()

   ckltoa()
          Opposite of atol()

   ckctoa()
          Returns character as string

   ckmakmsg()
          Used with ck?to?() as a safe sprintf() replacement for up to 4
          items

   ckmakxmsg()
          Like ckmakmsg() but accepts up to 12 items

   More about library functions in [32]Section 4.A.

   [ [33]Contents ] [ [34]C-Kermit ] [ [35]Kermit Home ]
    ________________________________________________________________________

  3.2. The "char" vs "unsigned char" Dilemma

   This is one of the most aggravating and vexing characteristics of the
   C language. By design, chars (and char *'s) are SIGNED. But in the
   modern era, however, we need to process characters that can have (or
   include) 8-bit values, as in the ISO Latin-1, IBM CP 850, or UTF-8
   character sets, 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.

   Some modern compilers (e.g. IBM, DEC, Microsoft) have options that say
   "make all chars be unsigned" (e.g. GCC "-funsigned-char") and we use
   them when they are available. Other compilers don't have this option,
   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.

   [ [36]Contents ] [ [37]C-Kermit ] [ [38]Kermit Home ]
    ________________________________________________________________________

  4. MODULES

   When C-Kermit is on the far end of a connection, it is said to be in
   remote mode. When C-Kermit has made a connection to another computer,
   it is in local mode. (If C-Kermit is "in the middle" of a multihop
   connection, it is still in local mode.)

   On another axis, C-Kermit can be in any of several major states:

   Command State
          Reading and writing from the job's controlling terminal or
          "console". In this mode, all i/o is handled by the Group E
          conxxx() (console i/o) routines.

   Protocol State
          Reading and writing from the communicatons device. In this
          mode, all i/o is handled by the Group E ttxxx() (terminal i/o)
          routines.

   Terminal State
          Reading from the keyboard with conxxx() routines and writing to
          the communications device with ttxxx() routines AND vice-versa.

   When in local mode, the console and communications device are
   distinct. During file transfer, Kermit may put up a file-transfer
   display on the console and sample the console for interruption
   signals.

   When in remote mode, the console and communications device are the
   same, and therefore there can be no file-transfer display on the
   console or interruptions from it (except for "in-band" interruptions
   such as ^C^C^C).

   [ [39]Contents ] [ [40]C-Kermit ] [ [41]Kermit Home ]
    ________________________________________________________________________

  4.A. Group A: Library Functions

   Library functions, strictly portable, can be used by all modules on
   all platforms: [42]ckclib.h, [43]ckclib.c.

   (To be filled in... For now, see [44]Section 3.1 and the comments in
   ckclib.c.)

   [ [45]Contents ] [ [46]C-Kermit ] [ [47]Kermit Home ]
    ________________________________________________________________________

  4.B. Group B: Kermit File Transfer

   The Kermit protocol kernel. These files, whose names start with "ckc
   are supposed to be totally portable C, and are expected to compile
   correctly on any platform with any C compiler. "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 B modules do not
   include any header files other than those that come with Kermit
   itself. They do not contain any library calls except from the standard
   C library (e.g. printf()). They most certainly do not contain any
   system calls. Files:

   [48]ckcsym.h
          For use by C compilers that don't allow -D on the command line.

   [49]ckcasc.h
          ASCII character symbol definitions.

   [50]ckcsig.h
          System-independent signal-handling definitions and prototypes.

   [51]ckcdeb.h
          Originally, debugging definitions. Now this file also contains
          all definitions and prototypes that are shared by all modules
          in all groups.

   [52]ckcker.h
          Kermit protocol symbol definitions.

   [53]ckcxla.h
          Character-set-related symbol definitions (see next section).

   [54]ckcmai.c
          The main program. This module contains the declarations of all
          the protocol-related global variables that are shared among the
          other modules.

   [55]ckcpro.w
          The protocol module itself, written in "wart", a lex-like
          preprocessor that is distributed with Kermit under the name
          CKWART.C.

   [56]ckcfns.c, [57]ckcfn2.c, [58]ckcfn3.c
          The protocol support functions used by the protocol module.

   [59]Group B modules may call upon functions from [60]Group E, but not
   from [61]Group D modules (with the single exception that the main
   program invokes the user interface, which is in Group D). (This last
   assertion is really only a conjecture.)

   [ [62]Contents ] [ [63]C-Kermit ] [ [64]Kermit Home ]
    ________________________________________________________________________

  4.C. Group C: Character-Set Conversion

   Character set translation tables and functions. Used by the [65]Group
   B, protocol modules, but may be specific to different computers. (So
   far, all character character sets supported by C-Kermit are supported
   in [66]ckuxla.c and [67]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.

   [68]ckcxla.h
          Character-set definitions usable by all versions of C-Kermit.

   ck?xla.h
          Character-set definitions for computer "?", e.g. [69]ckuxla.h
          for UNIX, [70]ckmxla.h for Macintosh.

   [71]ck?xla
          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.

   [72]ckcuni.h
          Unicode definitions

   [73]ckcuni.c
          Unicode module

   Here's how to add a new file character set in the original
   (non-Unicode modules). 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.

   To add a new Transfer Character Set, e.g. Latin Alphabet 9 (for the
   Euro symbol), again in the "old" character-set modules:

   In ckcxla.h:

          + Add a TC_xxxx definition and increase MAXTCSETS accordingly.

   In ck?xla.h (since any transfer charset is also a file charset):

          + Add an FC_xxxx definition and increase MAXFCSETS accordingly.

   In ck?xla.c:

          + Add a tcsinfo[] entry.
          + Make a tcstab[] keyword table entry.
          + Make an fcsinfo[] table entry.
          + Make an fcstab[] keyword table entry.
          + Make a tcstab[] keyword table entry.
          + If necessary, make a langinfo[] table entry.
          + Make entries in the function pointer arrays.
          + Provide any needed functions.

   As of C-Kermit 7.0, character sets are also handled in parallel by the
   new (and very large) Unicode module, ckcuni.[ch]. Eventually we should
   phase out the old way, described just above, and operate entirely in
   (and through) Unicode. The advantages are many. The disadvantages are
   size and performance. To add a character to the Unicode modules:

   In ckcuni.h:

          + (To be filled in...)

   In ckcuni.c:

          + (To be filled in...)

   [ [74]Contents ] [ [75]C-Kermit ] [ [76]Kermit Home ]
    ________________________________________________________________________

  4.D. Group D: 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 one provided is command-and
   prompt, with the ability to read commands from various sources: the
   console keyboard, a file, or a macro definition. 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, FTP client commands, etc.

   If you plan to imbed the [77]Group B, 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).

   [78]ckucmd.h
   [79]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 [80]Group E functions.

   [81]ckuusr.h
          Definitions of symbols used in Kermit's commands.

   ckuus*.c
          Kermit's interactive command parser, including the script
          programming language: [82]ckuusr.c (includes top-level keyword
          tables); [83]ckuus2.c (HELP command text); [84]ckuus3.c (most
          of the SET command); [85]ckuus4.c (includes variables and
          functions); ckuus[567].c (miscellaneous);

   [86]ckuusy.c
          The command-line-option parser.

   [87]ckuusx.c
          User interface functions common to both the interactive and
          command-line parsers.

   [88]ckuver.h
          Version heralds for different implementations.

   [89]ckuscr.c
          The (old, uucp-like) SCRIPT command

   [90]ckudia.c
          The DIAL command. Includes specific knowledge of many types of
          modems.

   Note that none of the above files is actually Unix-specific. Over time
   they have proven to be portable among all platforms where C-Kermit is
   built: Unix, VMS, AOS/VS, Amiga, OS-9, VOS, etc etc. Thus the third
   letter should more properly be "c", but changing it would be too
   confusing.

   ck?con.c, ckucns.c
          The CONNECT command. Terminal connection, and in some cases
          (Macintosh, Windows) also terminal emulation. NOTE: As of
          C-Kermit 7.0, there are two different CONNECT modules for UNIX:
          [91]ckucon.c -- the traditional, portable, fork()-based version
          -- and [92]ckucns.c, a new version that uses select() rather
          than forks so it can handle encryption. ckucns.c is the
          preferred version for Unix; ckucon.c is not likely to keep pace
          with it in terms of upgrades, etc. However, since select() is
          not portable to every platform, ckucon.c will be kept
          indefinitely for those platforms that can't use ckucns.c. NOTE:
          SunLink X.25 support is available only in ckucon.c.

   ck_*.*, ckuat*.*
          Modules having to do with authentication and encryption. Since
          the relaxation of USA export laws, they are included with the
          general source-code distribution. Secure C-Kermit binaries can
          be built using special targets in the standard makefile.
          However, secure prebuilt binaries may not be distributed.

   For other implementations, the files may, and probably do, have
   different names. For example, the Macintosh graphical user interface
   filenames start with "ckm". Kermit 95 uses the ckucmd and ckuus*
   modules, but has its own CONNECT command modules. 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. Our list
   of things to do is endless, and reorganizing the source is almost
   always at the bottom.

   The ckuus*.c modules (like many of the ckc*.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 [93]Group E
   platform-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, in theory, 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 [94]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 sstate (start state)
       variable 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 (hmmm, probably should be an unsigned long).

        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.

   [ [95]Contents ] [ [96]C-Kermit ] [ [97]Kermit Home ]
    ________________________________________________________________________

  4.E. Group E: Platform-Dependent I/O

   Platform-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 [98]ckufio.c (files), [99]ckutio.c (communications), and
   [100]ckusig.c (signal handling).

   For VMS, the files are [101]ckvfio.c, ckvtio.c, and [102]ckusig.c (VMS
   can use the same signal handling routines as Unix). 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 E modules contain both functions and global variables that
   are accessed by modules in the other groups. These are now described.

   (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. But that was a long time ago, probably circa
   Version 6.)

  4.E.1. Global 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. NOTE: DELCMD is used only in versions that do not
          provide their own built-in DELETE command.

   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. NOTE: DIRCMD is used only in versions that do not
          provide their own built-in DIRECTORY command.

   char *DIRCM2;
          Pointer to string containing command for listing files when a
          filespec is not given. (currently not used, handled in another
          way.)
          Example: char *DIRCMD2 = "/bin/ls -ld *";
          NOTE: DIRCMD2 is used only in versions that do not provide
          their own built-in DIRECTORY command.

   char *PWDCMD;
          Pointer to string containing command to display current
          directory.
          Example: char *PWDCMD = "pwd ";
          NOTE: PWDCMD is used only in versions that do not provide their
          own built-in PWD command.

   char *SPACMD;
          Pointer to command to display free disk space in current
          device/directory.
          Example: char *SPACMD = "df .";
          NOTE: SPACMD is used only in versions that do not provide their
          own built-in SPACE command.

   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. NOTE: SPACMD2 is used only in versions that do not
          provide their own built-in SPACE command.

   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. NOTE: TYPCMD is used only in versions that do not
          provide their own built-in TYPE command.

   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 OS, 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 by Group E module. Used by [103]ckcmai.c to initialize flow
          control variable.

   int dfloc;
          Default location. 0 = remote, 1 = local. Set by Group E 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 E module. Used by ckcmai.c to
          initialize parity variable.

   char *dftty;
          Default communication device. Set by Group E 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 VMS, etc. Example: char *dftty = CTTNAM;

   char *mtchs[];
          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;
          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;
          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;
          The maximum length for a filename, exclusive of any device or
          directory information, in the format of the host operating
          system.

   int maxpath;
          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;
          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.

   [ [104]Contents ] [ [105]C-Kermit ] [ [106]Kermit Home ]
    ________________________________________________________________________

  4.E.2. Functions

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

    4.E.2.1. File-Related Functions

   In most implementations, these are collected together into a module
   called ck?fio.c, where ? = "u" ([107]ckutio.c for Unix), "v"
   ([108]ckvtio.c for VMS), [109]etc. To be totally platform-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 mostly 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;
          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;
          Checks if the string is the name of an existing directory. The
          idea is to check whether the string can be "cd'd" to, so in
          some cases (e.g. DOS) it might also indicate any file
          structured device, such as a disk drive (like A:). Other
          nonzero returns indicate system-dependent information; e.g. in
          VMS isdir("[.FOO]") returns 1 but isdir("FOO.DIR;1") returns 2
          to indicate the directory-file name is in a format that needs
          conversion before it can be combined with a filename. Returns:
            0: not a directory (including any kind of error)
            1: it is an existing directory

   char *
          zfcdat(name) char *name;
          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(fn, buflen, buf) char * fn; int buflen; char * buf;
          Given the filename fn, the corresponding fully qualified,
          absolute filename is placed into the buffer buf, whose length
          is buflen. On failure returns a NULL pointer. On success
          returns a pointer to a struct zfnfp containing pointers to the
          full pathname and to just the filename, and an int giving the
          length of the full pathname. 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 or in the build-procedure CFLAGS.

   int
          zcmpfn(s1,s2) char * s2, * s2;
          Compares two filenames to see if they refer to the same.
          Internally, the arguments can be converted to fully qualified
          pathnames, e.g. with zfnqfp(), realpath(), or somesuch. In Unix
          or other systems where symbolic links exist, the link should be
          resolved before making the comparison or looking at the inodes.
          Returns:
            0: Files are not identical.
            1: Files are identical.

   int
          zfseek(pos) long pos;
          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;
          Changes current or default directory to the one given in
          dirnam. Returns:
            0: On failure.
            1: on success.

   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 (e.g. a
          directory);
           -1: on error (e.g. file does not exist, or fn is garbage);
          >=0: (length of file) if file exists and is readable.
          Also see isdir(), zgetfs().

   int
          zchkpid(pid) unsigned long pid;
          Returns:
            1: If the given process ID (e.g. pid in UNIX) is valid and
          active
            0: otherwise.

   long
          zgetfs(fn) char *fn;
          Gets the size of the given file, regardless of accessibility.
          Used for directory listings. Unlike zchki(), should return the
          size of any kind of file, even a directory. zgetfs() also
          should serve as a mini "get file info" function that can be
          used until we design a better one, by also setting some global
          variables:
            int zgfs_link   = 1/0 = file is (not) a symbolic link.
            int zgfs_dir    = 1/0 = file is (not) a directory.
            char linkname[] = if zgfs_link != 0, name of file link points
          to.
          Returns:
           -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;
          Checks to see if there is sufficient space to store the file
          named fn, which is len bytes long. 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. Returns:
           -1: on error.
            0: if there is not enough space.
            1: if there is enough space.

   int
          zchin(n,c) int n; int *c;
          Gets 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;
          Writes the character c to file number n. Returns:
           -1: on error.
            0: on success.

   int
          zclose(n) int n;
          Closes file number n. Returns:
           -1: on error.
            1: on success.

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

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

   char *
          ziperm(char * f)
          Returns a pointer to the system-dependent symbolic
          permissions/protection string for file f, or NULL upon failure.
          Used if CK_PERMS is defined. Example: In UNIX zgperm(f) might
          return "100770", but ziperm() might return "-rwxrwx---". In
          VMS, zgperm() would return a hexadecimal string, but ziperm()
          would return something like "(RWED,RWED,RE,)".

   char *
          zgtdir()
          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()
          Fill buffer from input file. 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 used only for sending files, and reads
          characters only from file number ZIFILE. zinfill() returns -1
          upon end of file, -2 upon fatal error, and -3 upon timeout
          (e.g. when reading from a pipe); 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;
          Strips device and directory, etc, from file specification fn,
          leaving only the filename (including "extension" or "filetype"
          -- the part after the dot). For example DUA0:[PROGRAMS]OOFA.C;3
          becomes OOFA.C, or /usr/fdc/oofa.c becomes oofa.c. Returns a
          pointer to result in fn2.

   int
          zsetperm(char * file, unsigned int code)
          Set permissions of file to given system-dependent code.   0: On
          failure.
            1: on success.

   int
          zsetroot(char * dir)
          Sets the root for the user's file access, like Unix chroot(),
          but does not require privilege. In Unix, this must be
          implemented entirely by Kermit's own file access routines.
          Returns:
            1: Success
           -1: Invalid argument
           -2:
           -3: Internal error
           -4: Access to given directory denied
           -5: New root not within old root

   int
          zinroot(char * file)
          If no root is set (zsetroot()), returns 1.
          Otherwise, if given file is in the root, returns 1.
          Otherwise, returns 0.

   VOID
          zltor(fn,fn2) char *fn1, *fn2;
          Local-To-Remote filename translation. OBSOLETE: replaced by
          nzltor() (q.v.). 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. If convert > 0,
          the regular conversions are done; if convert < 0, minimal
          conversions are done (we skip uppercasing the letters, we allow
          more than one period, etc; this can be used when we know our
          partner is UNIX or similar).

   #endif /* NZLTOR */

   int
          nzxpand(fn,flags) char *fn; int flags;
          Replaces zxpand(), which is obsolete as of C-Kermit 7.0.
          Call with:
            fn = Pointer to filename or pattern.
            flags = option bits:
              flags & ZX_FILONLY  Match regular files
              flags & ZX_DIRONLY  Match directories
              flags & ZX_RECURSE  Descend through directory tree
              flags & ZX_MATCHDOT Match "dot files"
              flags & ZX_NOBACKUP Don't match "backup files"
              flags & ZX_NOLINKS  Don't follow symlinks.

          Returns the number of files that match fn, with data structures
          set up so the first file (if any) will be returned by the next
          znext() call. If ZX_FILONLY and ZX_DIRONLY are both set, or
          neither one is set, files and directories are matched. Notes:

         1. It is essential that the number returned by nzxpand() reflect
            the actual number of filenames that will be returned by
            znext() calls. In other words:
  for (n = nzxpand(string,flags); n > 0; n--) {
      znext(buf);
      printf("%s\n", buf);
  }
            should print all the file names; no more, no less.
         2. In UNIX, DOS, OS-9, etc, where directories contain entries
            for themselves (.) and the superior directory (..), these
            should NOT be included in the list under any circumstances,
            including when ZX_MATCHDOT is set.
         3. Additional option bits might be added in the future, e.g. for
            sorting (sort by date/name/size, reverse/ascending, etc).
            Currently this is done only in higher level code (through a
            hack in which the nzxpand() exports its filename array, which
            is not portable because not all OS's can use this mechanism).

   int
          zmail(addr,fn) char *addr, fn;
          Send the local, existing file fn as e-mail to the address addr.
          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;
          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.
          Returns -1 on failure to create any of the needed directories.

   int
          zrmdir(path) char *path;
          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 that is guaranteed to be
          unique. If the file fn does not exist, then the new name is the
          same as fn; Otherwise, it's different. this function 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, so be sure to the
          result to a safe place before calling this function again.

   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 0 if there
          are no more filenames, with 0th element the array pointed to by
          fn set to NUL. If there is a filename, it is stored in the
          array pointed to by fn and a positive number is returned. NOTE:
          This is a change from earlier definitions of this function
          (pre-1999), which returned the number of files remaining; thus
          0 was the return value when returning the final file. However,
          no mainline code ever depended on the return value, so this
          change should be safe.

   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.

   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 relevant to complicated file systems
          like VMS (RMS), IBM MVS, etc, like blocksize, record length,
          organization, record format, carriage control, etc. Returns:
            0: on failure.
            1: on success.

   int
          zoutdump()
          Dumps a file 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;
          Prints the file with name fn on a local printer, with options
          p. 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;
          Changes the name of file fn to fn2. If fn2 is the name of an
          existing directory, or a file-structured device, then file fn
          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;
          Copies the source file to the destination. One file only. No
          wildcards. The destination string may be a filename or a
          directory name. Returns:
            0: on success.
           <0: on failure:
            -2: source file is not a regular file.
            -3: source file not found.
            -4: permission denied.
            -5: source and destination are the same file.
            -6: i/o error.
            -1: other error.

   char *
          zlocaltime(char *)
          Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time. Returns
          pointer to local date-time string "yyyymmdd hh:mm:ss" on
          success, NULL on failure.

   VOID
          zrtol(fn,fn2) char *fn, *fn2;
          Remote-To-Local filename translation. OBSOLETE: replaced by
          nzrtol(). Translates a "standard" filename 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
   int
          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;
          Fills in a Kermit file attribute structure for the file which
          is to be sent, namely the currently open ZIFILE. Note that this
          is not a very good design, but we're stuck with it. Callers
          must ensure that zsattr() is called only on real files, not on
          pipes, internally generated file-like objects such as server
          REMOTE command responses, etc. Returns:
           -1: on failure.
            0: on success with the structure filled in.
          If any string member is null, it should be ignored by the
          caller.
          If any numeric member is -1, 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
          pexitstatus
          zshcmd() and zsyscmd() should set this to the command's actual
          exit status code if possible.

   int
          zsyscmd(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
          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.

   VOID
          z_exec(s,args) char * s; char * args[];
          This one executes the command s (which is searched for using
          the system's normal searching mechanism, such as PATH in UNIX),
          with the given argument vector, which follows the conventions
          of UNIX argv[]: the name of the command pointed to by element
          0, the first arg by element 1, and so on. A null args[] pointer
          indicates the end of the arugment list. All open files must
          remain open so the exec'd process can use them. Returns only if
          unsuccessful.

   int
          zsinl(n,s,x) int n, x; char *s;
          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 failure.
          >= 0: on success, the number of characters actually written.

   int
          zstime(fn,yy,x) char *fn; struct zattr *yy; int x;
          Sets the creation date (and other attributes) of an existing
          file, or compares a file's creation date with a given date.
          Call with:

   fn: 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 file date. Other attributes
   in the struct can also be set, such as the protection/permission (See
   [110]Appendix I), when it makes sense (e.g. "yy->lprotect.val" can be
   set if the remote system ID matches the local one).
    x: 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;
          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.

   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;
          OBSOLETE: Replaced by nzxpand(), q.v.

   #ifdef ZXREWIND
   int
          zxrewind()
          Returns the number of files returned by the most recent
          nzxpand() call, and resets the list to the beginning so the
          next znext() call returns the first file. Returns -1 if zxpand
          has not yet been called. If this function is available,
          ZXREWIND should be defined; otherwise it should not be
          referenced.

   #endif /* ZXREWIND */

   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 executes
          in ordinary unprivileged user mode. If possible, xsystem()
          returns the return code of the command that was executed.

    4.E.2.2. IKSD Variables and Functions

   These must be implemented in any C-Kermit version that is to be
   installed as an Internet Kermit Service Daemon (IKSD). IKSD is
   expected to be started by the Internet Daemon (e.g. inetd) with its
   standard i/o redirected to the incoming connection.

   int ckxanon;
          Nonzero if anonymous logins allowed.

   extern int inserver;
          Nonzero if started in IKSD mode.

   extern int isguest;
          Nonzero if IKSD and user logged in anonymously.

   extern char * homdir;
          Pointer to user's home directory.

   extern char * anonroot;
          Pointer to file-system root for anonymous users.

   Existing functions must make "if (inserver && isguest)" checks for
   actions that would not be legal for guests: zdelete(), zrmdir(),
   zprint(), zmail(), etc.

   int
          zvuser(name) char * name;
          Verifies that user "name" exists and is allowed to log in. If
          the name is "ftp" or "anonymous" and ckxanon != 0, a guest
          login is set up. Returns 0 if user not allowed to log in,
          nonzero if user may log in.

   int
          zvpass(string) char * string;
          Verifies password of the user from the most recent zvuser()
          call. Returns nonzero if password is valid for user, 0 if it
          isn't. Makes any appropriate system log entries (IKSD logins,
          failed login attempts, etc). If password is valid, logs the
          user in as herself (if real user), or sets up restricted
          anonymous access if user is guest (e.g. changes file-system
          root to anonroot and sets isguest = 1).

   VOID
          zsyslog()
          Begins any desired system logging of an IKSD session.

   VOID
          zvlogout()
          Terminates an IKSD session. In most cases this is simply a
          wrapper for exit() or doexit(), with some system logging added.

    4.E.2.3. Privilege Functions

   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,
   e.g. setuid or setgid in Unix. 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 (see the [111]Unix C-Kermit Installation
   Instructions for discussion). 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 E 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 others?).

   int
          priv_ini()
          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()
          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()
          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()
          Turns privileges off in such a way that they cannot be turned
          back on. Returns:
            0 on success
            nonzero on failure

   int
          priv_chk()
          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

    4.E.2.4. 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
          by Kermit.

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

   int
          congks(timo) int timo;
          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)();
          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;
          Writes character c to the console terminal. Returns:
          0 on failure, 1 on success.

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

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

   int
          conoll(s) char *s;
          Writes 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()
          Restores 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();
          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.

    4.E.2.5. Communications 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 (serial-port) device; it could
   also be a network connection. 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).

          An external global variable, clsondisc, if nonzero, means that
          if a serial connection drops (carrier on-to-off transition
          detected by ttchk()), the device should be closed and released
          automatically.

   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()
          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()
          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()
          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()
          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()
          Turns off all pending timer interrupts.

   int
          ttinc(timo) int timo; (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)

   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).

   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 device is already open, or if the requested
                      device 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 [112]ckcnet.h:

  NET_TCPB 1   TCP/IP Berkeley (socket)  (implemented in [113]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 and receiving Kermit packets.

        Arguments:

              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.

   #ifdef TTSPDLIST
   long *
          ttspdlist()
          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.

   #endif /* TTSPDLIST */

   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;
          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:
            0: on failure.
            1: on success.

   int
          ttscarr(carrier) int carrier;
          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()
          Sends 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()
          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 VMS).

   int
          ttsspd(cps) int cps;
          For serial 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;
          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;
          Reads 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;
          Reads characters into the internal 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) On success, 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.

    4.E.2.6. Miscellaneous system-dependent functions

   VOID
          ztime(s) char **s;
          Returns 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 runtime 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. As a side
          effect, this routine can also fill in the following two
          external variables (which must be defined in the
          system-dependendent modules for each platform):
            long ztusec: Fraction of seconds of clock time, microseconds.
            long ztmsec: Fraction of seconds of clock time, milliseconds.
          If these variables are not set by zstime(), they remain at
          their initial value of -1L.

   int
          gtimer()
          Returns the current value of the elapsed time counter in
          seconds (see rtimer), or 0 on any kind of error.

   #ifdef GFTIMER
          CKFLOAT
          gftimer()
          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 the 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()
          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.

   [ [114]Contents ] [ [115]C-Kermit ] [ [116]Kermit Home ]
    ________________________________________________________________________

  4.F. Group F: 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 [117]ckutio.c. But this made it
   impossible to share this code with non-UNIX versions, like VMS,
   AOS/VS, OS/2, etc. So as of edit 168, network code has been separated
   out into its own module and header file, ckcnet.c and ckcnet.h:

     [118]ckcnet.h: Network-related symbol definitions.
     [119]ckcnet.c: Network i/o (TCP/IP, X.25, etc), shared by most
   platforms.
     [120]cklnet.c: Network i/o (TCP/IP, X.25, etc) specific to Stratus
   VOS.

   The routines and variables in these modules 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 A-D modules do not
   (and must not) know anything about these functions -- they continue to
   call the old Group E 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 E
          ttopen().

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

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

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

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

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

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

   int
          nettol()
          Send a "line" (sequence of bytes) to the network. Calling
          conventions same as Group E 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.

   VMS TCP/IP products have their 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.

   [ [121]Contents ] [ [122]C-Kermit ] [ [123]Kermit Home ]
      ______________________________________________________________________

    4.F.1. Telnet Protocol

   (This section needs a great deal of updating...)

   As of edit 195, Telnet protocol is split out into its own files, since
   it can be implemented in remote mode, which does not have a network
   connection:

      [124]ckctel.h: Telnet protocol symbol definitions.
      [125]ckctel.c: Telnet protocol.

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

   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.
      ______________________________________________________________________

    4.F.2. FTP Protocol

   (To be filled in...)
      ______________________________________________________________________

    4.F.3. HTTP Protocol

   (To be filled in...)
      ______________________________________________________________________

    4.F.4. X.25 Networks

   These routines were written SunLink X.25 and have since been adapted
   to at least on one other: IBM AIXLink/X.25.

   int
          x25diag()
          Reads and prints X.25 diagnostics

   int
          x25oobh()
          X.25 out of band signal handler

   int
          x25intr()
          Sends X.25 interrupt packet

   int
          x25reset()
          Resets X.25 virtual circuit

   int
          x25clear()
          Clear X.25 virtual circuit

   int
          x25stat()
          X.25 status

   int
          setqbit()
          Sets X.25 Q-bit

   int
          resetqbit()
          Resets X.25 Q-bit

   int
          x25xin()
          Reads n characters from X.25 circuit.

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

   [ [126]Contents ] [ [127]C-Kermit ] [ [128]Kermit Home ]
      ______________________________________________________________________

    4.F.5. Adding New Network Types

   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.

   [ [129]Contents ] [ [130]C-Kermit ] [ [131]Kermit Home ]
    ________________________________________________________________________

  4.G. Group G: 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
   [132]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:

   int
          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.

   VOID
          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.

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

   int
          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.

   [ [133]Contents ] [ [134]C-Kermit ] [ [135]Kermit Home ]
    ________________________________________________________________________

  4.H. Group H: Pseudoterminal Support

   (To be filled in...)
    ________________________________________________________________________

  4.I. Group I: Security

   (To be filled in...)

   [ [136]Contents ] [ [137]C-Kermit ] [ [138]Kermit Home ]
    ________________________________________________________________________

  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. High-order UNIX permission bits are not
   transmitted.

   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.

   [ [139]Top ] [ [140]Contents ] [ [141]C-Kermit Home ] [ [142]Kermit
   Home ]
     _________________________________________________________________


    C-Kermit Program Logic Manual / [143]The Kermit Project /
    [144]Columbia University / [145]kermit@columbia.edu / 10 April 2004

References

   1. http://www.columbia.edu/kermit/
   2. http://www.columbia.edu/
   3. http://www.columbia.edu/kermit/ckcplm.html
   4. http://www.columbia.edu/kermit/ckermit.html
   5. http://www.columbia.edu/kermit/index.html
   6. http://www.columbia.edu/kermit/ckcplm.html#x1
   7. http://www.columbia.edu/kermit/ckcplm.html#x2
   8. http://www.columbia.edu/kermit/ckcplm.html#x3
   9. http://www.columbia.edu/kermit/ckcplm.html#x4
  10. http://www.columbia.edu/kermit/ckcplm.html#x4.A
  11. http://www.columbia.edu/kermit/ckcplm.html#x4.B
  12. http://www.columbia.edu/kermit/ckcplm.html#x4.C
  13. http://www.columbia.edu/kermit/ckcplm.html#x4.D
  14. http://www.columbia.edu/kermit/ckcplm.html#x4.E
  15. http://www.columbia.edu/kermit/ckcplm.html#x4.F
  16. http://www.columbia.edu/kermit/ckcplm.html#x4.G
  17. http://www.columbia.edu/kermit/ckcplm.html#x4.H
  18. http://www.columbia.edu/kermit/ckcplm.html#x4.I
  19. http://www.columbia.edu/kermit/ckcplm.html#xa1
  20. http://www.columbia.edu/kermit/ckcplm.html#contents
  21. http://www.columbia.edu/kermit/ckcplm.html#contents
  22. http://www.columbia.edu/kermit/ckermit.html
  23. http://www.columbia.edu/kermit/index.html
  24. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
  25. http://www.columbia.edu/kermit/ckcplm.html#contents
  26. http://www.columbia.edu/kermit/ckermit.html
  27. http://www.columbia.edu/kermit/index.html
  28. http://www.columbia.edu/kermit/ckcplm.html#x3.2
  29. http://www.columbia.edu/kermit/ckcplm.html#contents
  30. http://www.columbia.edu/kermit/ckermit.html
  31. http://www.columbia.edu/kermit/index.html
  32. http://www.columbia.edu/kermit/ckcplm.html#x4.A
  33. http://www.columbia.edu/kermit/ckcplm.html#contents
  34. http://www.columbia.edu/kermit/ckermit.html
  35. http://www.columbia.edu/kermit/index.html
  36. http://www.columbia.edu/kermit/ckcplm.html#contents
  37. http://www.columbia.edu/kermit/ckermit.html
  38. http://www.columbia.edu/kermit/index.html
  39. http://www.columbia.edu/kermit/ckcplm.html#contents
  40. http://www.columbia.edu/kermit/ckermit.html
  41. http://www.columbia.edu/kermit/index.html
  42. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.h
  43. ftp://kermit.columbia.edu/kermit/c-kermit/ckclib.c
  44. http://www.columbia.edu/kermit/ckcplm.html#x3.1
  45. http://www.columbia.edu/kermit/ckcplm.html#contents
  46. http://www.columbia.edu/kermit/ckermit.html
  47. http://www.columbia.edu/kermit/index.html
  48. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsym.h
  49. ftp://kermit.columbia.edu/kermit/c-kermit/ckcasc.h
  50. ftp://kermit.columbia.edu/kermit/c-kermit/ckcsig.h
  51. ftp://kermit.columbia.edu/kermit/c-kermit/ckcdeb.h
  52. ftp://kermit.columbia.edu/kermit/c-kermit/ckcker.h
  53. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h
  54. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
  55. ftp://kermit.columbia.edu/kermit/c-kermit/ckcpro.w
  56. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfns.c
  57. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn2.c
  58. ftp://kermit.columbia.edu/kermit/c-kermit/ckcfn3.c
  59. http://www.columbia.edu/kermit/ckcplm.html#x4.B
  60. http://www.columbia.edu/kermit/ckcplm.html#x4.E
  61. http://www.columbia.edu/kermit/ckcplm.html#x4.D
  62. http://www.columbia.edu/kermit/ckcplm.html#contents
  63. http://www.columbia.edu/kermit/ckermit.html
  64. http://www.columbia.edu/kermit/index.html
  65. http://www.columbia.edu/kermit/ckcplm.html#x4.B
  66. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.c
  67. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h
  68. ftp://kermit.columbia.edu/kermit/c-kermit/ckcxla.h
  69. ftp://kermit.columbia.edu/kermit/c-kermit/ckuxla.h
  70. ftp://kermit.columbia.edu/kermit/c-kermit/ckmxla.h
  71. ftp://kermit.columbia.edu/kermit/c-kermit/ck?xla
  72. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.h
  73. ftp://kermit.columbia.edu/kermit/c-kermit/ckcuni.c
  74. http://www.columbia.edu/kermit/ckcplm.html#contents
  75. http://www.columbia.edu/kermit/ckermit.html
  76. http://www.columbia.edu/kermit/index.html
  77. http://www.columbia.edu/kermit/ckcplm.html#x4.B
  78. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.h
  79. ftp://kermit.columbia.edu/kermit/c-kermit/ckucmd.c
  80. http://www.columbia.edu/kermit/ckcplm.html#x4.E
  81. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.h
  82. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusr.c
  83. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus2.c
  84. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus3.c
  85. ftp://kermit.columbia.edu/kermit/c-kermit/ckuus4.c
  86. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusy.c
  87. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
  88. ftp://kermit.columbia.edu/kermit/c-kermit/ckuver.h
  89. ftp://kermit.columbia.edu/kermit/c-kermit/ckuscr.c
  90. ftp://kermit.columbia.edu/kermit/c-kermit/ckudia.c
  91. ftp://kermit.columbia.edu/kermit/c-kermit/ckucon.c
  92. ftp://kermit.columbia.edu/kermit/c-kermit/ckucns.c
  93. http://www.columbia.edu/kermit/ckcplm.html#x4.E
  94. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
  95. http://www.columbia.edu/kermit/ckcplm.html#contents
  96. http://www.columbia.edu/kermit/ckermit.html
  97. http://www.columbia.edu/kermit/index.html
  98. ftp://kermit.columbia.edu/kermit/c-kermit/ckufio.c
  99. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
 100. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c
 101. ftp://kermit.columbia.edu/kermit/c-kermit/ckvfio.c
 102. ftp://kermit.columbia.edu/kermit/c-kermit/ckusig.c
 103. ftp://kermit.columbia.edu/kermit/c-kermit/ckcmai.c
 104. http://www.columbia.edu/kermit/ckcplm.html#contents
 105. http://www.columbia.edu/kermit/ckermit.html
 106. http://www.columbia.edu/kermit/index.html
 107. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
 108. ftp://kermit.columbia.edu/kermit/c-kermit/ckvtio.c
 109. http://www.columbia.edu/kermit/ckcplm.html#x2
 110. http://www.columbia.edu/kermit/ckcplm.html#xa1
 111. http://www.columbia.edu/kermit/ckuins.html
 112. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
 113. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
 114. http://www.columbia.edu/kermit/ckcplm.html#contents
 115. http://www.columbia.edu/kermit/ckermit.html
 116. http://www.columbia.edu/kermit/index.html
 117. ftp://kermit.columbia.edu/kermit/c-kermit/ckutio.c
 118. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.h
 119. ftp://kermit.columbia.edu/kermit/c-kermit/ckcnet.c
 120. ftp://kermit.columbia.edu/kermit/c-kermit/cklnet.c
 121. http://www.columbia.edu/kermit/ckcplm.html#contents
 122. http://www.columbia.edu/kermit/ckermit.html
 123. http://www.columbia.edu/kermit/index.html
 124. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.h
 125. ftp://kermit.columbia.edu/kermit/c-kermit/ckctel.c
 126. http://www.columbia.edu/kermit/ckcplm.html#contents
 127. http://www.columbia.edu/kermit/ckermit.html
 128. http://www.columbia.edu/kermit/index.html
 129. http://www.columbia.edu/kermit/ckcplm.html#contents
 130. http://www.columbia.edu/kermit/ckermit.html
 131. http://www.columbia.edu/kermit/index.html
 132. ftp://kermit.columbia.edu/kermit/c-kermit/ckuusx.c
 133. http://www.columbia.edu/kermit/ckcplm.html#contents
 134. http://www.columbia.edu/kermit/ckermit.html
 135. http://www.columbia.edu/kermit/index.html
 136. http://www.columbia.edu/kermit/ckcplm.html#contents
 137. http://www.columbia.edu/kermit/ckermit.html
 138. http://www.columbia.edu/kermit/index.html
 139. http://www.columbia.edu/kermit/ckcplm.html#top
 140. http://www.columbia.edu/kermit/ckcplm.html#contents
 141. http://www.columbia.edu/kermit/ckermit.html
 142. http://www.columbia.edu/kermit/index.html
 143. http://www.columbia.edu/kermit/index.html
 144. http://www.columbia.edu/
 145. mailto:kermit@columbia.edu