[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244] [0245] [0246] [0247] [0248] [0249] [0250] [0251] [0252] [0253] [0254] [0255] [0256] [0257] [0258] [0259] [0260] [0261] [0262] [0263] [0264] [0265] [0266] [0267] [0268] [0269] [0270] [0271] [0272] [0273] [0274] [0275] [0276] [0277] [0278] [0279] [0280] [0281] [0282] [0283] [0284] [0285] [0286] [0287] [0288] [0289] [0290] [0291] [0292] [0293] [0294] [0295] [0296] [0297] [0298] [0299] [0300] [0301] [0302] [0303] [0304] [0305] [0306] [0307] [0308] [0309] [0310] [0311] [0312] [0313] [0314] [0315] [0316] [0317] [0318] [0319] [0320] [0321] [0322] [0323] [0324] [0325] [0326] [0327] [0328] [0329] [0330] [0331] [0332] [0333] [0334] [0335] [0336] [0337] [0338] [0339] [0340] [0341] [0342] [0343] [0344] [0345] [0346] [0347] [0348] [0349] [0350] [0351] [0352] [0353] [0354] [0355] [0356] [0357] [0358] [0359] [0360] [0361] [0362] [0363] [0364] [0365] [0366] [0367] [0368] [0369] [0370] [0371] [0372] [0373] [0374] [0375] [0376] [0377] [0378] [0379] [0380] [0381] [0382] [0383] [0384] [0385] [0386] [0387] [0388] [0389] [0390] [0391] [0392] [0393] [0394] [0395] [0396] [0397] [0398] [0399] [0400] [0401] [0402] [0403] [0404] [0405] [0406] [0407] [0408] [0409] [0410] [0411] [0412] [0413] [0414] [0415] [0416] [0417] [0418] [0419] [0420] [0421] [0422] [0423] [0424] [0425] [0426] [0427] [0428] [0429] [0430] [0431] [0432] [0433] [0434] [0435] [0436] [0437] [0438] [0439] [0440] [0441] [0442] [0443] [0444] [0445] [0446] [0447] [0448] [0449] [0450] [0451] [0452] [0453] [0454] [0455] [0456] [0457] [0458] [0459] [0460] [0461] [0462] [0463] [0464] [0465] [0466] [0467] [0468] [0469] [0470] [0471] [0472] [0473] [0474] [0475] [0476] [0477] [0478] [0479] [0480] [0481] [0482] [0483] [0484] [0485] [0486] [0487] [0488] [0489] [0490] [0491] [0492] [0493] [0494] [0495] [0496] [0497] [0498] [0499] [0500] [0501] [0502] [0503] [0504] [0505] [0506] [0507] [0508] [0509] [0510] [0511] [0512] [0513] [0514] [0515] [0516] [0517] [0518] [0519] [0520] [0521] [0522] [0523] [0524] [0525] [0526] [0527] [0528] [0529] [0530] [0531] [0532] [0533] [0534] [0535] [0536] [0537] [0538] [0539] [0540] [0541] [0542] [0543] [0544] [0545] [0546] [0547] [0548] [0549] [0550] [0551] [0552] [0553] [0554] [0555] [0556] [0557] [0558] [0559] [0560] [0561] [0562] [0563] [0564] [0565] [0566] [0567] [0568] [0569] [0570] [0571] [0572] [0573] [0574] [0575] [0576] [0577] [0578] [0579] [0580] [0581] [0582] [0583] [0584] [0585] [0586] [0587] [0588] [0589] [0590] [0591] [0592] [0593] [0594] [0595] [0596] [0597] [0598] [0599] [0600] [0601] [0602] [0603] [0604] [0605] [0606] [0607] [0608] [0609] [0610] [0611] [0612] [0613] [0614] [0615] [0616] [0617] [0618] [0619] [0620] [0621] [0622] [0623] [0624] [0625] [0626] [0627] [0628] [0629] [0630] [0631] [0632] [0633] [0634] [0635] [0636] [0637] [0638] [0639] [0640] [0641] [0642] [0643] [0644] [0645] [0646] [0647] [0648] [0649] [0650] [0651] [0652] [0653] [0654] [0655] [0656] [0657] [0658] [0659] [0660] [0661] [0662] [0663] [0664] [0665] [0666] [0667] [0668] [0669] [0670] [0671] [0672] [0673] [0674] [0675] [0676] [0677] [0678] [0679] [0680] [0681] [0682] [0683] [0684] [0685] [0686] [0687] [0688] [0689] [0690] [0691] [0692] [0693] [0694] [0695] [0696] [0697] [0698] [0699] [0700] [0701] [0702] [0703] [0704] [0705] [0706] [0707] [0708] [0709] [0710] [0711] [0712] [0713] [0714] [0715] [0716] [0717] [0718] [0719] [0720] [0721] [0722] [0723] [0724] [0725] [0726] [0727] [0728] [0729] [0730] [0731] [0732] [0733] [0734] [0735] [0736] [0737] [0738] [0739] [0740] [0741] [0742] [0743] [0744] [0745] [0746] [0747] [0748] [0749] [0750] [0751] [0752] [0753] [0754] [0755] [0756] [0757] [0758] [0759] [0760] [0761] [0762] [0763] [0764] [0765] [0766] [0767] [0768] [0769] [0770] [0771] [0772] [0773] [0774] [0775] [0776] [0777] [0778] [0779] [0780] [0781] [0782] [0783] [0784] [0785] [0786] [0787] [0788] [0789] [0790] [0791] [0792] [0793] [0794] [0795] [0796] [0797] [0798] [0799] [0800] [0801] [0802] [0803] [0804] [0805] [0806] [0807] [0808] [0809] [0810] [0811] [0812] [0813] [0814] [0815] [0816] [0817] [0818] [0819] [0820] [0821] [0822] [0823] [0824] [0825] [0826] [0827] [0828] [0829] [0830] [0831] [0832] [0833] [0834] [0835] [0836] [0837] [0838] [0839] [0840] [0841] [0842] [0843] [0844] [0845] [0846] [0847] [0848] [0849] [0850] [0851] [0852] [0853] [0854] [0855] [0856] [0857] [0858] [0859] [0860] [0861] [0862] [0863] [0864] [0865] [0866] [0867] [0868] [0869] [0870] [0871] [0872] [0873] [0874] [0875] [0876] [0877] [0878] [0879] [0880] [0881] [0882] [0883] [0884] [0885] [0886] [0887] [0888] [0889] [0890] [0891] [0892] [0893] [0894] [0895] [0896] [0897] [0898] [0899] [0900] [0901] [0902] [0903] [0904] [0905] [0906] [0907] [0908] [0909] [0910] [0911] [0912] [0913] [0914] [0915] [0916] [0917] [0918] [0919] [0920] [0921] [0922] [0923] [0924] [0925] [0926] [0927] [0928] [0929] [0930] [0931] [0932] [0933] [0934] [0935] [0936] [0937] [0938] [0939] [0940] [0941] [0942] [0943] [0944] [0945] [0946] [0947] [0948] [0949] [0950] [0951] [0952] [0953] [0954] [0955] [0956] [0957] [0958] [0959] [0960] [0961] [0962] [0963] [0964] [0965] [0966] [0967] [0968] [0969] [0970] [0971] [0972] [0973] [0974] [0975] [0976] [0977] [0978] [0979] [0980] [0981] [0982] [0983] [0984] [0985] [0986] [0987] [0988] [0989] [0990] [0991] [0992] [0993] [0994] [0995] [0996] [0997] [0998] [0999] [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] [3077] [3078] [3079] [3080] [3081] [3082] [3083] [3084] [3085] [3086] [3087] [3088] [3089] [3090] [3091] [3092] [3093] [3094] [3095] [3096] [3097] [3098] [3099] [3100] [3101] [3102] [3103] [3104] [3105] [3106] [3107] [3108] [3109] [3110] [3111] [3112] [3113] [3114] [3115] [3116] [3117] [3118] [3119] [3120] [3121] [3122] [3123] [3124] [3125] [3126] [3127] [3128] [3129] [3130] [3131] [3132] [3133] [3134] [3135] [3136] [3137] [3138] [3139] [3140] [3141] [3142] [3143] [3144] [3145] [3146] [3147] [3148] [3149] [3150] [3151] [3152] [3153] [3154] [3155] [3156] [3157] [3158] [3159] [3160] [3161] [3162] [3163] [3164] [3165] [3166] [3167] [3168] [3169] [3170] [3171] [3172] [3173] [3174] [3175] [3176] [3177] [3178] [3179] [3180] [3181] [3182] [3183] [3184] [3185] [3186] [3187] [3188] [3189] [3190] [3191] [3192] [3193] [3194] [3195] [3196] [3197] [3198] [3199] [3200] [3201] [3202] [3203] [3204] [3205] [3206] [3207] [3208] [3209] [3210] [3211] [3212] [3213] [3214] [3215] [3216] [3217] [3218] [3219] [3220] [3221] [3222] [3223] [3224] [3225] [3226] [3227] [3228] [3229] [3230] [3231] [3232] [3233] [3234] [3235] [3236] [3237] [3238] [3239] [3240] [3241] [3242] [3243] [3244] [3245] [3246] [3247] [3248] [3249] [3250] [3251] [3252] [3253] [3254] [3255] [3256] [3257] [3258] [3259] [3260] [3261] [3262] [3263] [3264] [3265] [3266] [3267] [3268] [3269] [3270] [3271] [3272] [3273] [3274] [3275] [3276] [3277] [3278] [3279] [3280] [3281] [3282] [3283] [3284] [3285] [3286] [3287] [3288] [3289] [3290] [3291] [3292] [3293] [3294] [3295] [3296] [3297] [3298] [3299] [3300] [3301] [3302] [3303] [3304] [3305] [3306] [3307] [3308] [3309] [3310] [3311] [3312] [3313] [3314] [3315] [3316] [3317] [3318] [3319] [3320] [3321] [3322] [3323] [3324] [3325] [3326] [3327] [3328] [3329] [3330] [3331] [3332] [3333] [3334] [3335] [3336] [3337] [3338] [3339] [3340] [3341] [3342] [3343] [3344] [3345] [3346] [3347] [3348] [3349] [3350] [3351] [3352] [3353] [3354] [3355] [3356] [3357] [3358] [3359] [3360] [3361] [3362] [3363] [3364] [3365] [3366] [3367] [3368] [3369] [3370] [3371] [3372] [3373] [3374] [3375] [3376] [3377] [3378] [3379] [3380] [3381] [3382] [3383] [3384] [3385] [3386] [3387] [3388] [3389] [3390] [3391] [3392] [3393] [3394] [3395] [3396] [3397] [3398] [3399] [3400] [3401] [3402] [3403] [3404] [3405] [3406] [3407] [3408] [3409] [3410] [3411] [3412] [3413] [3414] [3415] [3416] [3417] [3418] [3419] [3420] [3421] [3422] [3423] [3424] [3425] [3426] [3427] [3428] [3429] [3430] [3431] [3432] [3433] [3434] [3435] [3436] [3437] [3438] [3439] [3440] [3441] [3442] [3443] [3444] [3445] [3446] [3447] [3448] [3449] [3450] [3451] [3452] [3453] [3454] [3455] [3456] [3457] [3458] [3459] [3460] [3461] [3462] [3463] [3464] [3465] [3466] [3467] [3468] [3469] [3470] [3471] [3472] [3473] [3474] [3475] [3476] [3477] [3478] [3479] [3480] [3481] [3482] [3483] [3484] [3485] [3486] [3487] [3488] [3489] [3490] [3491] [3492] [3493] [3494] [3495] [3496] [3497] [3498] [3499] [3500] [3501] [3502] [3503] [3504] [3505] [3506] [3507] [3508] [3509] [3510] [3511] [3512] [3513] [3514] [3515] [3516] [3517] [3518] [3519] [3520] [3521] [3522] [3523] [3524] [3525] [3526] [3527] [3528] [3529] [3530] [3531] [3532] [3533] [3534] [3535] [3536] [3537] [3538] [3539] [3540] [3541] [3542] [3543] [3544] [3545] [3546] [3547] [3548] [3549] [3550] [3551] [3552] [3553] [3554] [3555] [3556] [3557] [3558] [3559] [3560] [3561] [3562] [3563] [3564] [3565] [3566] [3567] [3568] [3569] [3570] [3571] [3572] [3573] [3574] [3575] [3576] [3577] [3578] [3579] [3580] [3581] [3582] [3583] [3584] [3585] [3586] [3587] [3588] [3589] [3590] [3591] [3592] [3593] [3594] [3595] [3596] [3597] [3598] [3599] [3600] [3601] [3602] [3603] [3604] [3605] [3606] [3607] [3608] [3609] [3610] [3611] [3612] [3613] [3614] [3615] [3616] [3617] [3618] [3619] [3620] [3621] [3622] [3623] [3624] [3625] [3626] [3627] [3628] [3629] [3630] [3631] [3632] [3633] [3634] [3635] [3636] [3637] [3638] [3639] [3640] [3641] [3642] [3643] [3644] [3645] [3646] [3647] [3648] [3649] [3650] [3651] [3652] [3653] [3654] [3655] [3656] [3657] [3658] [3659] [3660] [3661] [3662] [3663] [3664] [3665] [3666] [3667] [3668] [3669] [3670] [3671] [3672] [3673] [3674] [3675] [3676] [3677] [3678] [3679] [3680] [3681] [3682] [3683] [3684] [3685] [3686] [3687] [3688] [3689] [3690] [3691] [3692] [3693] [3694] [3695] [3696] [3697] [3698] [3699] [3700] [3701] [3702] [3703] [3704] [3705] [3706] [3707] [3708] [3709] [3710] [3711] [3712] [3713] [3714] [3715] [3716] [3717] [3718] [3719] [3720] [3721] [3722] [3723] [3724] [3725] [3726] [3727] [3728] [3729] [3730] [3731] [3732] [3733] [3734] [3735] [3736] [3737] [3738] [3739] [3740] [3741] [3742] [3743] [3744] [3745] [3746] [3747] [3748] [3749] [3750] [3751] [3752] [3753] [3754] [3755] [3756] [3757] [3758] [3759] [3760] [3761] [3762] [3763] [3764] [3765] [3766] [3767] [3768] [3769] [3770] [3771] [3772] [3773] [3774] [3775] [3776] [3777] [3778] [3779] [3780] [3781] [3782] [3783] [3784] [3785] [3786] [3787] [3788] [3789] [3790] [3791] [3792] [3793] [3794] [3795] [3796] [3797] [3798] [3799] [3800] [3801] [3802] [3803] [3804] [3805] [3806] [3807] [3808] [3809] [3810] [3811] [3812] [3813] [3814] [3815] [3816] [3817] [3818] [3819] [3820] [3821] [3822] [3823] [3824] [3825] [3826] [3827] [3828] [3829] [3830] [3831] [3832] [3833] [3834] [3835] [3836] [3837] [3838] [3839] [3840] [3841] [3842] [3843] [3844] [3845] [3846] [3847] [3848] [3849] [3850] [3851] [3852] [3853] [3854] [3855] [3856] [3857] [3858] [3859] [3860] [3861] [3862] [3863] [3864] [3865] [3866] [3867] [3868] [3869] [3870] [3871] [3872] [3873] [3874] [3875] [3876] [3877] [3878] [3879] [3880] [3881] [3882] [3883] [3884] [3885] [3886] [3887] [3888] [3889] [3890] [3891] [3892] [3893] [3894] [3895] [3896] [3897] [3898] [3899] [3900] [3901] [3902] [3903] [3904] [3905] [3906] [3907] [3908] [3909] [3910] [3911] [3912] [3913] [3914] [3915] [3916] [3917] [3918] [3919] [3920] [3921] [3922] [3923] [3924] [3925] [3926] [3927] [3928] [3929] [3930] [3931] [3932] [3933] [3934] [3935] [3936] [3937] [3938] [3939] [3940] [3941] [3942] [3943] [3944] [3945] [3946] [3947] [3948] [3949] [3950] [3951] [3952] [3953] [3954] [3955] [3956] [3957] [3958] [3959] [3960] [3961] [3962] [3963] [3964] [3965] [3966] [3967] [3968] [3969] [3970] [3971] [3972] [3973] [3974] [3975] [3976] [3977] [3978] [3979] [3980] [3981] [3982] [3983] [3984] [3985] [3986] [3987] [3988] [3989] [3990] [3991] [3992] [3993] [3994] [3995] [3996] [3997] [3998] [3999] [4000] [4001] [4002] [4003] [4004] [4005] [4006] [4007] [4008] [4009] [4010] [4011] [4012] [4013] [4014] [4015] [4016] [4017] [4018] [4019] [4020] [4021] [4022] [4023] [4024] [4025] [4026] [4027] [4028] [4029] [4030] [4031] [4032] [4033] [4034] [4035] [4036] [4037] [4038] [4039] [4040] [4041] [4042] [4043] [4044] [4045] [4046] [4047] [4048] [4049] [4050] [4051] [4052] [4053] [4054] [4055] [4056] [4057] [4058] [4059] [4060] [4061] [4062] [4063] [4064] [4065] [4066] [4067] [4068] [4069] [4070] [4071] [4072] [4073] [4074] [4075] [4076] [4077] [4078] [4079] [4080] [4081] [4082] [4083] [4084] [4085] [4086] [4087] [4088] [4089] [4090] [4091] [4092] [4093] [4094] [4095] [4096] [4097] [4098] [4099] [4100] [4101] [4102] [4103] [4104] [4105] [4106] [4107] [4108] [4109] [4110] [4111] [4112] [4113] [4114] [4115] [4116] [4117] [4118] [4119] [4120] [4121] [4122] [4123] [4124] [4125] [4126] [4127] [4128] [4129] [4130] [4131] [4132] [4133] [4134] [4135] [4136] [4137] [4138] [4139] [4140] [4141] [4142] [4143] [4144] [4145] [4146] [4147] [4148] [4149] [4150] [4151] [4152] [4153] [4154] [4155] [4156] [4157] [4158] [4159] [4160] [4161] [4162] [4163] [4164] [4165] [4166] [4167] [4168] [4169] [4170] [4171] [4172] [4173] [4174] [4175] [4176] [4177] [4178] [4179] [4180] [4181] [4182] [4183] [4184] [4185] [4186] [4187] [4188] [4189] [4190] [4191] [4192] [4193] [4194] [4195] [4196] [4197] [4198] [4199] [4200] [4201] [4202] [4203] [4204] [4205] [4206] [4207] [4208] [4209] [4210] [4211] [4212] [4213] [4214] [4215] [4216] [4217] [4218] [4219] [4220] [4221] [4222] [4223] [4224] [4225] [4226] [4227] [4228] [4229] [4230] [4231] [4232] [4233] [4234] [4235] [4236] [4237] [4238] [4239] [4240] [4241] [4242] [4243] [4244] [4245] [4246] [4247] [4248] [4249] [4250] [4251] [4252] [4253] [4254] [4255] [4256] [4257] [4258] [4259] [4260] [4261] [4262] [4263] [4264] [4265] [4266] [4267] [4268] [4269] [4270] [4271] [4272] [4273] [4274] [4275] [4276] [4277] [4278] [4279] [4280] [4281] [4282] [4283] [4284] [4285] [4286] [4287] [4288] [4289] [4290] [4291] [4292] [4293] [4294] [4295] [4296] [4297] [4298] [4299] [4300] [4301] [4302] [4303] [4304] [4305] [4306] [4307] [4308] [4309] [4310] [4311] [4312] [4313] [4314] [4315] [4316] [4317] [4318] [4319] [4320] [4321] [4322] [4323] [4324] [4325] [4326] [4327] [4328] [4329] [4330] [4331] [4332] [4333] [4334] [4335] [4336] [4337] [4338] [4339] [4340] [4341] [4342] [4343] [4344] [4345] [4346] [4347] [4348] [4349] [4350] [4351] [4352] [4353] [4354] [4355] [4356] [4357] [4358] [4359] [4360] [4361] [4362] [4363] [4364] [4365] [4366] [4367] [4368] [4369] [4370] [4371] [4372] [4373] [4374] [4375] [4376] [4377] [4378] [4379] [4380] [4381] [4382] [4383] [4384] [4385] [4386] [4387] [4388] [4389] [4390] [4391] [4392] [4393] [4394] [4395] [4396] [4397] [4398] [4399] [4400] [4401] [4402] [4403] [4404] [4405] [4406] [4407] [4408] [4409] [4410] [4411] [4412] [4413] [4414] [4415] [4416] [4417] [4418] [4419] [4420] [4421] [4422] [4423] [4424] [4425] [4426] [4427] [4428] [4429] [4430] [4431] [4432] [4433] [4434] [4435] [4436] [4437] [4438] [4439] [4440] [4441] [4442] [4443] [4444] [4445] [4446] [4447] [4448] [4449] [4450] [4451] [4452] [4453] [4454] [4455] [4456] [4457] [4458] [4459] [4460] [4461] [4462] [4463] [4464] [4465] [4466] [4467] [4468] [4469] [4470] [4471] [4472] [4473] [4474] [4475] [4476] [4477] [4478] [4479] [4480] [4481] [4482] [4483] [4484] [4485] [4486] [4487] [4488] [4489] [4490] [4491] [4492] [4493] [4494] [4495] [4496] [4497] [4498] [4499] [4500] [4501] [4502] [4503] [4504] [4505] [4506] [4507] [4508] [4509] [4510] [4511] [4512] [4513] [4514] [4515] [4516] [4517] [4518] [4519] [4520] [4521] [4522] [4523] [4524] [4525] [4526] [4527] [4528] [4529] [4530] [4531] [4532] [4533] [4534] [4535] [4536] [4537] [4538] [4539] [4540] [4541] [4542] [4543] [4544] [4545] [4546] [4547] [4548] [4549] [4550] [4551] [4552] [4553] [4554] [4555] [4556] [4557] [4558] [4559] [4560] [4561] [4562] [4563] [4564] [4565] [4566] [4567] [4568] [4569] [4570] [4571] [4572] [4573] [4574] [4575] [4576] [4577] [4578] [4579] [4580] [4581] [4582] [4583] [4584] [4585] [4586] [4587] [4588] [4589] [4590] [4591] [4592] [4593] [4594] [4595] [4596] [4597] [4598] [4599] [4600] [4601] [4602] [4603] [4604] [4605] [4606] [4607] [4608] [4609] [4610] [4611] [4612] [4613] [4614] [4615] [4616] [4617] [4618] [4619] [4620] [4621] [4622] [4623] [4624] [4625] [4626] [4627] [4628] [4629] [4630] [4631] [4632] [4633] [4634] [4635] [4636] [4637] [4638] [4639] [4640] [4641] [4642] [4643] [4644] [4645] [4646] [4647] [4648] [4649] [4650] [4651] [4652] [4653] [4654] [4655] [4656] [4657] [4658] [4659] [4660] [4661] [4662] [4663] [4664] [4665] [4666] [4667] [4668] [4669] [4670] [4671] [4672] [4673] [4674] [4675] [4676] [4677] [4678] [4679] [4680] [4681] [4682] [4683] [4684] [4685] [4686] [4687] [4688] [4689] [4690] [4691] [4692] [4693] [4694] [4695] [4696] [4697] [4698] [4699] [4700] [4701] [4702] [4703] [4704] [4705] [4706] [4707] [4708] [4709] [4710] [4711] [4712] [4713] [4714] [4715] [4716] [4717] [4718] [4719] [4720] [4721] [4722] [4723] [4724] [4725] [4726] [4727] [4728] [4729] [4730] [4731] [4732] [4733] [4734] [4735] [4736] [4737] [4738] [4739] [4740] [4741] [4742] [4743] [4744] [4745] [4746] [4747] [4748] [4749] [4750] [4751] [4752] [4753] [4754] [4755] [4756] [4757] [4758] [4759] [4760] [4761] [4762] [4763] [4764] [4765] [4766] [4767] [4768] [4769] [4770] [4771] [4772] [4773] [4774] [4775] [4776] [4777] [4778] [4779] [4780] [4781] [4782] [4783] [4784] [4785] [4786] [4787] [4788] [4789] [4790] [4791] [4792] [4793] [4794] [4795] [4796] [4797] [4798] [4799] [4800] [4801] [4802] [4803] [4804] [4805] [4806] [4807] [4808] [4809] [4810] [4811] [4812] [4813] [4814] [4815] [4816] [4817] [4818] [4819] [4820] [4821] [4822] [4823] [4824] [4825] [4826] [4827] [4828] [4829] [4830] [4831] [4832] [4833] [4834] [4835] [4836] [4837] [4838] [4839] [4840] [4841] [4842] [4843] [4844] [4845] [4846] [4847] [4848] [4849] [4850] [4851] [4852] [4853] [4854] [4855] [4856] [4857] [4858] [4859] [4860] [4861] [4862] [4863] [4864] [4865] [4866] [4867] [4868] [4869] [4870] [4871] [4872] [4873] [4874] [4875] [4876] [4877] [4878] [4879] [4880] [4881] [4882] [4883] [4884] [4885] [4886] [4887] [4888] [4889] [4890] [4891] [4892] [4893] [4894] [4895] [4896] [4897] [4898] [4899] [4900] [4901] [4902] [4903] [4904] [4905] [4906] [4907] [4908] [4909] [4910] [4911] [4912] [4913] [4914] [4915] [4916] [4917] [4918] [4919] [4920] [4921] [4922] [4923] [4924] [4925] [4926] [4927] [4928] [4929] [4930] [4931] [4932] [4933] [4934] [4935] [4936] [4937] [4938] [4939] [4940] [4941] [4942] [4943] [4944] [4945] [4946] [4947] [4948] [4949] [4950] [4951] [4952] [4953] [4954] [4955] [4956] [4957] [4958] [4959] [4960] [4961] [4962] [4963] [4964] [4965] [4966] [4967] [4968] [4969] [4970] [4971] [4972] [4973] [4974] [4975] [4976] [4977] [4978] [4979] [4980] [4981] [4982] [4983] [4984] [4985] [4986] [4987] [4988] [4989] [4990] [4991] [4992] [4993] [4994] [4995] [4996] [4997] [4998] [4999] [5000] [5001] [5002] [5003] [5004] [5005] [5006] [5007] [5008] [5009] [5010] [5011] [5012] [5013] [5014] [5015] [5016] [5017] [5018] [5019] [5020] [5021] [5022] [5023] [5024] [5025] [5026] [5027] [5028] [5029] [5030] [5031] [5032] [5033] [5034] [5035] [5036] [5037] [5038] [5039] [5040] [5041] [5042] [5043] [5044] [5045] [5046] [5047] [5048] [5049] [5050] [5051] [5052] [5053] [5054] [5055] [5056] [5057] [5058] [5059] [5060] [5061] [5062] [5063] [5064] [5065] [5066] [5067] [5068] [5069] [5070] [5071] [5072] [5073] [5074] [5075] [5076] [5077] [5078] [5079] [5080] [5081] [5082] [5083] [5084] [5085] [5086] [5087] [5088] [5089] [5090] [5091] [5092] [5093] [5094] [5095] [5096] [5097] [5098] [5099] [5100] [5101] [5102] [5103] [5104] [5105] [5106] [5107] [5108] [5109] [5110] [5111] [5112] [5113] [5114] [5115] [5116] [5117] [5118] [5119] [5120] [5121] [5122] [5123] [5124] [5125] [5126] [5127] [5128] [5129] [5130] [5131] [5132] [5133] [5134] [5135] [5136] [5137] [5138] [5139] [5140] [5141] [5142] [5143] [5144] [5145] [5146] [5147] [5148] [5149] [5150] [5151] [5152] [5153] [5154] [5155] [5156] [5157] [5158] [5159] [5160] [5161] [5162] [5163] [5164] [5165] [5166] [5167] [5168] [5169] [5170] [5171] [5172] [5173] [5174] [5175] [5176] [5177] [5178] [5179] [5180] [5181] [5182] [5183] [5184] [5185] [5186] [5187] [5188] [5189] [5190] [5191] [5192] [5193] [5194] [5195] [5196] [5197] [5198] [5199] [5200] [5201] [5202] [5203] [5204] [5205] [5206] [5207] [5208] [5209] [5210] [5211] [5212] [5213] [5214] [5215] [5216] [5217] [5218] [5219] [5220] [5221] [5222] [5223] [5224] [5225] [5226] [5227] [5228] [5229] [5230] [5231] [5232] [5233] [5234] [5235] [5236] [5237] [5238] [5239] [5240] [5241] [5242] [5243] [5244] [5245] [5246] [5247] [5248] [5249] [5250] [5251] [5252] [5253] [5254]
/*****************************************************************************/ /* Upd.c This module implements a full multi-threaded, AST-driven, asynchronous file and directory update facility. It provides for directory navigation, allowing subdirectories to be created, moved to, listed and deleted. Files within directories may be selected for viewing, update, copying and deletion. The module honours the directory access controls implemented by the directory module (e.g. ".WWW_HIDDEN", etc., see Dir.c). It allows the creation or update of "text/*" files via an editing page. The <textarea></textarea> tag widget is used as the edit window. The file editing page also has custom functionality for providing for the partial administration of HTTPd server configuration files. This module behaves as if it was an external script :^). This allows the generic script processing functionality of the the request module to provide all necessary parsing of the script and file components of the path, as well as the all-important authorization checking of these. The script component of the path is detected before an external script is launched, and the request redirected to this module. This has certain efficiencies as well as allowing a "generic" module to provide some of the functionality for server configuration. This module does its own query string parsing. An essential component of this modules functionality is the ability to generate a redirection. This allows the parent directory and name to be reconstructed as a path and then processed as if a new request. Although resulting in a higher overhead this considerably simplifies the handling of these requests. VERSION HISTORY --------------- 14-SEP-2019 MGD bugfix; UpdEnd() call HTAdminEnd() (e.g. $HTL) 12-NOV-2017 MGD bugfix; (long-standing) always use UpdEnd() not SysDclAst() 28-SEP-2013 MGD some refinements to Upd..() layout and functionality 03-AUG-2013 MGD bugfix; UpdFileRename() ACCVIO with AuthAccessEnable() 10-MAR-2010 JPP bugfix; UpdBegin() [goto] processing 23-AUG-2009 MGD WasdCss[] and some refinements 11-AUG-2007 MGD AuthAccessEnable() to control access refine edit with a little JavaScript 26-AUG-2003 MGD rework access to server configuration files 15-AUG-2003 MGD where CDATA constraints make using entity impossible use a field name of hidden$lf and ^ substituted for it 08-MAR-2003 MGD set html= directory listing header and footer, there are now three directory listing styles implementing set dir=style[=default|wasd1|wasd2|abi] 15-OCT-2002 MGD demo mode ignores .WWW_HIDDEN, etc. 05-OCT-2002 MGD refine VMS security profile usage 24-SEP-2002 MGD add AuthAccessReadCheck() to special-case file parse/open() in UpdEditFileBegin() 23-AUG-2002 MGD supply fab$b_rfm and fab$b_rat as file copy fields to allow PUT.C to set these attributes identically to the original, modify formatting for SRI and PWK ODS encodings, bugfix; change protection for directories, bugfix; enable SYSPRV to rename (ACP remove) file, bugfix; enable SYSPRV to change protection (ACP modify) file 27-APR-2002 MGD make SYSPRV enabled ASTs asynchronous 02-FEB-2002 MGD rework file processing due to request body processing changes 03-JAN-2002 MGD bugfix; server admin revise 04-AUG-2001 MGD support module WATCHing 15-FEB-2001 MGD refine 'view' and 'list' redirection 22-DEC-2000 MGD allow navigation on wildcard file specification, provide special case edit (only) HTL list and CA verification files 29-JUN-2000 MGD bugfix; ODS-5 file rename 18-JUN-2000 MGD support site log update 04-MAR-2000 MGD support ODS-2 and ODS-5 using ODS module, substantial rework of entire module, remove browser check for file upload (many now support) 10-OCT-1999 MGD change AuthCheckVmsUserAccess() always supply 'rqptr' 04-APR-1999 MGD bugfix; rule check still included (woops, obsoleted in v5.3) 07-NOV-1998 MGD WATCH facility 12-MAR-1998 MGD add file protection selector 24-FEB-1998 MGD request scheme ("http:" or "https:") for hard-wired "http:" 18-OCT-1997 MGD facility to wildcard file deletes 17-AUG-1997 MGD message database, internationalized file date/times, SYSUAF-authenticated users security-profile 07-JUL-1997 MGD apparently MSIE 3.0ff allows file upload 30-JUN-1997 MGD bugfix; rename failed without SYSPRV (wonders will never) 12-APR-1997 MGD extended tree facility to providing general directory tree 25-MAR-1997 MGD added tree and filter capabilities 01-FEB-1997 MGD new for HTTPd version 4 (adapted from the UPD script) */ /*****************************************************************************/ #ifdef WASD_VMS_V7 #undef _VMS__V6__SOURCE #define _VMS__V6__SOURCE #undef __VMS_VER #define __VMS_VER 70000000 #undef __CRTL_VER #define __CRTL_VER 70000000 #endif /* standard C header files */ #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* VMS related header files */ #include <iodef.h> #include <libdef.h> #include <libdtdef.h> #include <rmsdef.h> #include <rms.h> #include <ssdef.h> #include <stsdef.h> /* application related header */ #include "wasd.h" #define WASD_MODULE "UPD" /****************/ /* global stuff */ /****************/ /* number of rows in directory and file lists */ #define NAVIGATE_SIZE 15 #define REFRESH_SYMBOL "⟳"; /* this could be relocated without change by using a mapping rule */ #define UPD_HELP_PATH "/httpd/-/UpdHelp.html" /* The preview note is introduced at the start of a file being previewed. See PUT.C module for how it is further processed. Experimentation (Navigator 3 and MSIE 3) has shown it can contain text but no page or line layup tags (e.g. <br>). Here is a choice between an animated GIF and text. */ #define UPD_PREVIEW_NOTE_PLAIN "***** PREVIEW *****^^" #ifndef UPD_PREVIEW_TEXT #define UPD_PREVIEW_NOTE_HTML \ "<IMG SRC="/httpd/-/UpdPreview.gif" \ ALT="-PREVIEW- "><BR>" #define UPD_PREVIEW_NOTE_HTML_NEWLINE "^" #define UPD_PREVIEW_NOTE_MENU_NEWLINE "<BR>" #else #define UPD_PREVIEW_NOTE_HTML \ "<FONT size=\"1\" COLOR="#ff0000">\ <SUP><BLINK><B>-PREVIEW-</B></BLINK></SUP>\ </FONT>&nbsp;&nbsp;" #define UPD_PREVIEW_NOTE_HTML_NEWLINE "^" #define UPD_PREVIEW_NOTE_MENU_NEWLINE "<BR>" #endif /* UPD_PREVIEW_TEXT */ char UpdProtectionListFao [] = "!AZ name=\"protection\">\n\ <option value=\"aa00\"!AZ>!AZ\n\ <option value=\"fa00\"!AZ>!AZ\n\ <option value=\"ff00\"!AZ>!AZ\n\ </select>\n"; char UpdLayout [64]; /********************/ /* external storage */ /********************/ extern BOOL CliDemo, NaturalLanguageEnglish, OdsExtended; extern int ToLowerCase[], ToUpperCase[]; extern unsigned long SysPrvMask[]; extern char* DayName[]; extern char ClientHostName[], ClientIpAddressString[], DirBrowsableFileName[], DirHiddenFileName[], DirNopFileName[], DirNosFileName[], DirNopsFileName[], DirNoWildFileName[], ErrorSanityCheck[], ServerHostPort[], SoftwareID[]; extern ACCOUNTING_STRUCT *AccountingPtr; extern CONFIG_STRUCT Config; extern MSG_STRUCT Msgs; extern WATCH_STRUCT Watch; /*****************************************************************************/ /* Begin processing an update request by allocating an update task structure, processing the query string, and initiating the required function. */ void UpdBegin ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction ) { BOOL DoCopy, DoDirProtect, DoFileProtect, DoFileRename, DoTree, Navigate, NameIsPeriod, SubmitCopy, SubmitCreate, SubmitDelete, SubmitDirProtect, SubmitEdit, SubmitFilter, SubmitFileRename, SubmitFileProtect, SubmitGoto, SubmitList, SubmitMkdir, SubmitRmdir, SubmitTree, SubmitView, WatchThisOne; int status; unsigned short Length; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *qptr, *sptr, *zptr, *WatchPathPtr; char AsName [256], DoThis [128], FieldName [128], FieldValue [256], Location [ODS_MAX_FILE_NAME_LENGTH+1], Name [128], Scratch [ODS_MAX_FILE_NAME_LENGTH+1], SubmitButton [16]; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdBegin()"); /* if there is a request body this will be called again as an AST */ if (!(tkptr = rqptr->UpdTaskPtr)) { /* set up the task structure (only ever one per request!) */ rqptr->UpdTaskPtr = tkptr = (UPD_TASK*) VmGetHeap (rqptr, sizeof(UPD_TASK)); OdsStructInit (&tkptr->FileOds, false); OdsStructInit (&tkptr->SearchOds, false); /* don't want to try this when called as an AST! */ tkptr->NextTaskFunction = NextTaskFunction; if (!rqptr->AccountingDone++) InstanceGblSecIncrLong (&AccountingPtr->DoUpdateCount); } if (rqptr->rqHeader.Method == HTTP_METHOD_POST && !rqptr->rqBody.DataPtr) { /* read all the request body (special case) then AST back */ BodyReadBegin (rqptr, &UpdBegin, &BodyProcessReadAll); return; } /* must be after task allocation as function may be called as an AST */ if (ERROR_REPORTED (rqptr)) { /* previous error, cause threaded processing to unravel */ UpdEnd (rqptr); return; } if (!tkptr->ProtectionMask) tkptr->ProtectionMask = PUT_DEFAULT_FILE_PROTECTION; /* terminate the path string at the first character of any file name part */ zptr = (sptr = tkptr->PathInfoDir) + sizeof(tkptr->PathInfoDir)-1; for (cptr = rqptr->rqHeader.PathInfoPtr; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; while (sptr > tkptr->PathInfoDir && *sptr != '/') sptr--; if (sptr > tkptr->PathInfoDir) sptr++; *sptr = '\0'; tkptr->PathInfoDirLength = sptr - tkptr->PathInfoDir; if (WATCHING (rqptr, WATCH_RESPONSE)) WatchThisOne = true; else WatchThisOne = false; if (strsame (rqptr->ScriptName, ADMIN_SCRIPT_TREE, sizeof(ADMIN_SCRIPT_TREE)-1)) { /***********/ /* tree of */ /***********/ tkptr->UpdateTree = false; if (WatchThisOne) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "TREEOF !AZ !AZ", rqptr->rqHeader.PathInfoPtr, rqptr->ParseOds.ExpFileName); if (!rqptr->ParseOds.ExpFileNameLength) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_DIRECTORY), FI_LI); UpdEnd (rqptr); return; } if (rqptr->ParseOds.Nam_fnb & NAM$M_WILD_VER || rqptr->ParseOds.Nam_fnb & NAM$M_EXP_VER) tkptr->FormatTreeLikeVms = true; else tkptr->FormatTreeLikeVms = false; /* get any file name, type, version from request specification */ zptr = (sptr = tkptr->FileNamePart) + sizeof(tkptr->FileNamePart)-1; for (cptr = rqptr->ParseOds.NamNamePtr; *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; rqptr->rqResponse.PreExpired = Config.cfDir.PreExpired; /* scan the query string looking for "expired=[yes|no|true|false|1|0]" */ for (cptr = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr : ""; *cptr; cptr++) { /* experience shows both make it easier! */ if (TOLO(*cptr) == 'e' && (strsame (cptr, "expired=", 8)) || strsame (cptr, "expire=", 7)) { if (cptr[7] == '=') cptr += 8; else cptr += 7; /* "true", "yes", "1", "false", "no" or "0" */ if (TOLO(*cptr) == 't' || TOLO(*cptr) == 'y' || *cptr == '1') rqptr->rqResponse.PreExpired = true; else if (TOLO(*cptr) == 'f' || TOLO(*cptr) == 'n' || *cptr == '0') rqptr->rqResponse.PreExpired = false; break; } while (*cptr && *cptr != '&') cptr++; if (*cptr) cptr++; } UpdTreeBegin (rqptr); return; } /**********/ /* update */ /**********/ AsName[0] = DoThis[0] = Name[0] = SubmitButton[0] = '\0'; tkptr->CxR[0] = tkptr->FileProtectionList[0] = tkptr->ProtectionList[0] = '\0'; DoCopy = DoDirProtect = DoFileProtect = DoFileRename = DoTree = SubmitCreate = SubmitCopy = SubmitDelete = SubmitDirProtect = SubmitEdit = SubmitFileProtect = SubmitFilter = SubmitFileRename = SubmitGoto = SubmitList = SubmitMkdir = SubmitRmdir = SubmitTree = SubmitView = false; if (rqptr->rqHeader.Method == HTTP_METHOD_POST) qptr = rqptr->rqBody.DataPtr; else if (rqptr->rqHeader.QueryStringLength) qptr = rqptr->rqHeader.QueryStringPtr; else qptr = ""; if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchDataFormatted ("!&Z\n", qptr); while (*qptr) { status = StringParseQuery (&qptr, FieldName, sizeof(FieldName), FieldValue, sizeof(FieldValue)); if (VMSnok (status)) { /* error occured */ if (status == SS$_IVCHAR) rqptr->rqResponse.HttpStatus = 400; rqptr->rqResponse.ErrorTextPtr = "parsing query string"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /********************/ /* get field values */ /********************/ if (strsame (FieldName, "as", -1)) { cptr = FieldValue; zptr = (sptr = AsName) + sizeof(AsName); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; } else if (strsame (FieldName, "cxr", -1)) { cptr = FieldValue; zptr = (sptr = tkptr->CxR) + sizeof(tkptr->CxR); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; } else if (strsame (FieldName, "do", -1)) { /* primarily for use from HTADMIN module */ cptr = FieldValue; zptr = (sptr = DoThis) + sizeof(DoThis); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; } else if (strsame (FieldName, "name", -1)) { cptr = FieldValue; zptr = (sptr = Name) + sizeof(Name); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; } else if (strsame (FieldName, "protection", -1)) { if (isxdigit(FieldValue[0])) tkptr->ProtectionMask = strtol (FieldValue, NULL, 16); } else if (TOLO(FieldName[0]) == 'd' && FieldName[1] == '-') { if (strsame (FieldName, "d-copy", -1)) DoCopy = true; else if (strsame (FieldName, "d-dirprotect", -1)) DoDirProtect = true; else if (strsame (FieldName, "d-fileprotect", -1)) DoDirProtect = true; else if (strsame (FieldName, "d-filerename", -1)) DoFileRename = true; else if (strsame (FieldName, "d-tree", -1)) DoTree = true; } else if (TOLO(FieldName[0]) == 's' && FieldName[1] == '-') { if (strsame (FieldName, "s-copy", -1)) SubmitCopy = true; else #ifdef UPD_CREATE if (strsame (FieldName, "s-create", -1)) SubmitCreate = true; else #endif /* UPD_CREATE */ if (strsame (FieldName, "s-delete", -1)) SubmitDelete = true; else if (strsame (FieldName, "s-dirprotect", -1)) SubmitDirProtect = true; else if (strsame (FieldName, "s-edit", -1)) SubmitEdit = true; else if (strsame (FieldName, "s-fileprotect", -1)) SubmitFileProtect = true; else #ifdef UPD_FILTER if (strsame (FieldName, "s-filter", -1)) SubmitFilter = true; else #endif /* UPD_FILTER */ if (strsame (FieldName, "s-goto", -1)) SubmitGoto = true; else if (strsame (FieldName, "s-list", -1)) SubmitList = true; else if (strsame (FieldName, "s-mkdir", -1)) SubmitMkdir = true; else if (strsame (FieldName, "s-filerename", -1)) SubmitFileRename = true; else if (strsame (FieldName, "s-rmdir", -1)) SubmitRmdir = true; else if (strsame (FieldName, "s-tree", -1)) SubmitTree = true; else if (strsame (FieldName, "s-view", -1)) SubmitView = true; else { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_QUERY_FIELD), FI_LI); UpdEnd (rqptr); return; } strcpy (SubmitButton, FieldName+2); } else if (strsame (FieldName, "virtual", -1)) { /* just ignore (from Admin Menu) */ } else { rqptr->rqResponse.HttpStatus = 403; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_QUERY_FIELD), FI_LI); UpdEnd (rqptr); return; } } /**************************/ /* end parse query string */ /**************************/ /* ensure something has been entered into the file name field */ if (SAME2(Name, '.\0')) { NameIsPeriod = true; Name[0] = '\0'; } else NameIsPeriod = false; if (SubmitDelete) { /***************/ /* delete file */ /***************/ if (!Name[0] && !AsName[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_FILENAME), FI_LI); UpdEnd (rqptr); return; } if (WatchThisOne) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE !AZ !AZ!AZ", SubmitButton, rqptr->rqHeader.PathInfoPtr, AsName[0] ? AsName : Name); UpdConfirmDelete (rqptr, AsName[0] ? AsName : Name, ""); return; } if (SubmitDirProtect || SubmitFileProtect) { /*********************/ /* change protection */ /*********************/ if (!Name[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_FILENAME), FI_LI); UpdEnd (rqptr); return; } if (WatchThisOne) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE !AZ !AZ!AZ", SubmitButton, rqptr->rqHeader.PathInfoPtr, AsName[0] ? AsName : Name); if (SubmitDirProtect) UpdConfirmProtect (rqptr, AsName[0] ? AsName : Name, "/"); else UpdConfirmProtect (rqptr, AsName[0] ? AsName : Name, ""); return; } if (SubmitMkdir) { /***********************/ /* create subdirectory */ /***********************/ if (!AsName[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_DIRECTORY), FI_LI); UpdEnd (rqptr); return; } if (WatchThisOne) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE !AZ !AZ!AZ", SubmitButton, rqptr->rqHeader.PathInfoPtr, AsName); UpdConfirmMkdir (rqptr, AsName); return; } if (SubmitRmdir) { /***********************/ /* delete subdirectory */ /***********************/ if (!Name[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_DIRECTORY), FI_LI); UpdEnd (rqptr); return; } if (WatchThisOne) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE !AZ !AZ!AZ", SubmitButton, rqptr->rqHeader.PathInfoPtr, Name); UpdConfirmDelete (rqptr, Name, "/"); return; } if (SubmitCopy || #ifdef UPD_CREATE SubmitCreate || #endif /* UPD_CREATE */ SubmitDirProtect || SubmitEdit || SubmitFileProtect || #ifdef UPD_FILTER SubmitFilter || #endif /* UPD_FILTER */ SubmitGoto || SubmitList || SubmitMkdir || SubmitFileRename || SubmitTree || SubmitView) { /******************************/ /* REDIRECT (via "Location:") */ /******************************/ if (SubmitCopy) { if (!Name[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_SRC_FILENAME), FI_LI); UpdEnd (rqptr); return; } if (!AsName[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_DST_FILENAME), FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!&%AZ!&%AZ!&%AZ?d-copy=1&as=!&%AZ&protection=!4XL", rqptr->ScriptName, rqptr->rqHeader.PathInfoPtr, Name, AsName, tkptr->ProtectionMask); } else #ifdef UPD_CREATE if (SubmitCreate) { if (!AsName[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_FILENAME), FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!&%AZ!&%AZ!&%AZ", rqptr->ScriptName, rqptr->rqHeader.PathInfoPtr, AsName); } else #endif /* UPD_CREATE */ if (SubmitEdit) { if (!Name[0] && !AsName[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_FILENAME), FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!&%AZ!&%AZ!&%AZ!AZ!&%AZ?protection=!4XL", rqptr->ScriptName, rqptr->rqHeader.PathInfoPtr, AsName[0] && !Name[0] ? AsName : Name, AsName[0] && Name[0] ? "?as=" : "", AsName[0] && Name[0] ? AsName : "", tkptr->ProtectionMask); } else #ifdef UPD_FILTER if (SubmitFilter) { if (!Name[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_FILENAME), FI_LI); UpdEnd (rqptr); return; } if (!AsName[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_FILTER), FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!AZ!&%AZ!&%AZ!&%AZ", AsName[0] ? "/" : "", AsName, rqptr->rqHeader.PathInfoPtr, AsName); } else #endif /* UPD_FILTER */ if (SubmitFileProtect) { if (!Name[0] && !AsName) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_FILENAME), FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!&%AZ!&%AZ!&%AZ?d-fileprotect=1&protection=!4XL", rqptr->ScriptName, rqptr->rqHeader.PathInfoPtr, AsName[0] ? AsName : Name, tkptr->ProtectionMask); } else if (SubmitGoto) { if (!Name[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_DIRECTORY), FI_LI); UpdEnd (rqptr); return; } if (MATCH2 (Name, "..")) { /* parent directory */ sptr = (cptr = tkptr->PathInfoDir) + tkptr->PathInfoDirLength; while (sptr > cptr && *sptr != '/') sptr--; if (sptr > cptr && *sptr == '/') sptr--; while (sptr > cptr && *sptr != '/') sptr--; if (sptr > cptr && *sptr == '/') sptr++; if (sptr == cptr) { rqptr->rqResponse.HttpStatus = 400; rqptr->rqResponse.ErrorTextPtr = "../"; rqptr->rqResponse.ErrorOtherTextPtr = "[-]"; ErrorVmsStatus (rqptr, RMS$_DNF, FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!&%AZ!#&%AZ?protection=!4XL", rqptr->ScriptName, sptr-cptr, cptr, tkptr->ProtectionMask); } else status = FaoToBuffer (Location, sizeof(Location), &Length, "!&%AZ!&%AZ!&%AZ/?protection=!4XL", rqptr->ScriptName, rqptr->rqHeader.PathInfoPtr, Name, tkptr->ProtectionMask); } else if (SubmitList) { if (!Name[0] && !NameIsPeriod) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_DIRECTORY), FI_LI); UpdEnd (rqptr); return; } /* update directory listing layout including protection */ if (!UpdLayout[0]) { zptr = (sptr = UpdLayout) + sizeof(UpdLayout); for (cptr = "&layout="; *cptr; *sptr++ = *cptr++); if (Config.cfDir.DefaultLayout[0]) cptr = Config.cfDir.DefaultLayout; else cptr = DEFAULT_DIR_LAYOUT; while (*cptr) { if (sptr >= zptr) break; if (*cptr == ':') { if (sptr < zptr) *sptr++ = *cptr++; if (*cptr && sptr < zptr) *sptr++ = *cptr++; continue; } if (TOUP(*cptr) == 'P') { cptr++; while (*cptr == '_') cptr++; continue; } if (TOUP(*cptr) == 'S') { if (sptr < zptr) *sptr++ = *cptr++; if (*cptr == ':') { *sptr++ = *cptr++; if (*cptr && sptr < zptr) *sptr++ = *cptr++; } if (sptr < zptr) *sptr++ = '_'; if (sptr < zptr) *sptr++ = '_'; if (sptr < zptr) *sptr++ = 'P'; while (*cptr == '_' && sptr < zptr) *sptr++ = *cptr++; continue; } if (sptr < zptr) *sptr++ = *cptr++; } if (sptr >= zptr) { UpdLayout[0] = '\0'; ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!AZ//!&%AZ!&%AZ!AZ!&%AZ?httpd=index&expired=yes!AZ", rqptr->ServicePtr->RequestSchemeNamePtr, rqptr->rqHeader.PathInfoPtr, Name, Name[0] ? "/" : "", AsName[0] ? AsName : "*.*", UpdLayout); } else if (SubmitMkdir) { if (!AsName[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_DIRECTORY), FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!&%AZ!&%AZ!&%AZ/?d-mkdir=1", rqptr->ScriptName, rqptr->rqHeader.PathInfoPtr, AsName); } else if (SubmitFileRename) { if (!Name[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_CUR_FILENAME), FI_LI); UpdEnd (rqptr); return; } if (!AsName[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_NEW_FILENAME), FI_LI); UpdEnd (rqptr); return; } if (strsame (Name, AsName, -1)) { ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_RENAME_SAME), FI_LI); UpdEnd (rqptr); return; } UpdConfirmRename (rqptr, Name, AsName); return; } else if (SubmitTree) { if (!Name[0] && !NameIsPeriod) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_DIRECTORY), FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!&%AZ!&%AZ!&%AZ!AZ?d-tree=1", rqptr->ScriptName, rqptr->rqHeader.PathInfoPtr, Name, Name[0] ? "/" : ""); } else if (SubmitView) { if (!Name[0]) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_FILENAME), FI_LI); UpdEnd (rqptr); return; } status = FaoToBuffer (Location, sizeof(Location), &Length, "!AZ//!&%AZ!&%AZ", rqptr->ServicePtr->RequestSchemeNamePtr, rqptr->rqHeader.PathInfoPtr, Name); } else { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_ACTION), FI_LI); UpdEnd (rqptr); return; } if (VMSnok (status) || status == SS$_BUFFEROVF) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaoToBuffer()"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } ResponseLocation (rqptr, Location, Length); if (WatchThisOne) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE !AZ !AZ", SubmitButton, Location); UpdEnd (rqptr); return; } /********************************/ /* navigate, edit, copy, rename */ /********************************/ if (DoTree) { /********/ /* tree */ /********/ if (WatchThisOne) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE treeof !AZ", rqptr->ParseOds.ExpFileName); /* remove the query string that got us here */ rqptr->rqHeader.QueryStringPtr = NULL; rqptr->rqHeader.QueryStringLength = 0; rqptr->rqResponse.PreExpired = PRE_EXPIRE_UPD_TREE_OF; tkptr->UpdateTree = true; UpdTreeBegin (rqptr); return; } if (DoFileProtect || DoDirProtect) { /*********************/ /* change protection */ /*********************/ /* this function supplies it's own watch response item */ UpdProtection (rqptr); return; } if (DoFileRename) { /***************/ /* file rename */ /***************/ /* this function supplies it's own watch response item */ UpdFileRename (rqptr, Name, AsName); return; } if (DoCopy) { /********/ /* copy */ /********/ /* this function supplies it's own watch response item */ UpdCopyFileBegin (rqptr, AsName); return; } /********************/ /* protection lists */ /********************/ strcpy (cptr = Scratch, MsgFor (rqptr, MSG_UPD_PROTECTION_LIST)); vecptr = FaoVector; *vecptr++ = "<select"; if (tkptr->ProtectionMask == 0xaa00) *vecptr++ = " selected"; else *vecptr++ = ""; *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; if (tkptr->ProtectionMask == 0xfa00) *vecptr++ = " selected"; else *vecptr++ = ""; *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; if (tkptr->ProtectionMask == 0xff00) *vecptr++ = " selected"; else *vecptr++ = ""; *vecptr++ = cptr; status = FaolToBuffer (tkptr->ProtectionList, sizeof(tkptr->ProtectionList), 0, UpdProtectionListFao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); /* bang an id into this other list */ vecptr = FaoVector; *vecptr++ = "<select id=\"fileprot\""; status = FaolToBuffer (tkptr->FileProtectionList, sizeof(tkptr->FileProtectionList), 0, UpdProtectionListFao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); /**********************/ /* what are we doing? */ /**********************/ if (strsame (rqptr->rqHeader.PathInfoPtr, ADMIN_REVISE, sizeof(ADMIN_REVISE)-1)) Navigate = false; else if (strsame (rqptr->rqHeader.PathInfoPtr, ADMIN_VS_REVISE, sizeof(ADMIN_VS_REVISE)-1)) Navigate = false; else if (rqptr->ParseOds.Nam_fnb & NAM$M_WILDCARD) Navigate = true; else if (rqptr->ParseOds.NamNameLength || rqptr->ParseOds.NamTypeLength || rqptr->ParseOds.NamVersionLength) Navigate = false; else Navigate = true; if (Navigate) { /******************/ /* let's navigate */ /******************/ /* this function supplies it's own watch response item */ UpdNavigateBegin (rqptr); return; } /*****************/ /* edit the file */ /*****************/ /* this function supplies it's own watch response item */ UpdEditFileBegin (rqptr, NULL, AsName); } /*****************************************************************************/ /* All requests processed by the UPD.C module should call this function at the end of processing. */ void UpdEnd (REQUEST_STRUCT *rqptr) { int status; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdEnd()"); tkptr = rqptr->UpdTaskPtr; if (tkptr->FileOds.Fab.fab$w_ifi) OdsClose (&tkptr->FileOds, NULL, rqptr); /* ensure parse internal data structures are released */ OdsParseRelease (&tkptr->FileOds); OdsParseRelease (&tkptr->SearchOds); /* indicate the task has concluded (allocated memory freed with request) */ rqptr->UpdTaskPtr = NULL; if (rqptr->HTAdminTaskPtr) HTAdminEnd (rqptr); else SysDclAst (tkptr->NextTaskFunction, rqptr); } /*****************************************************************************/ /* Begin by setting up a search for all directories. */ void UpdNavigateBegin (REQUEST_STRUCT *rqptr) { static char ResponseFao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>!AZ !AZ</title>\n\ <style type=\"text/css\">\n\ input[type=submit], input[type=reset] { min-width:6em; }\n\ </style>\n\ <script language=\"JavaScript\">\n\ <!!--\n\ function dirDblClick() {\n\ document.getElementById(\'s-goto\').click();\n\ }\n\ function fileDblClick() {\n\ document.getElementById(\'s-view-open\').click();\n\ }\n\ function theName(what) {\n\ var name = document.getElementById(what+\'as\').value;\n\ var id = document.getElementById(what+\'name\');\n\ id = id.options[id.selectedIndex];\n\ if (id && !!name.length) name = id.value;\n\ if (name.length) return escape(name);\n\ return null;\n\ }\n\ function dirList() {\n\ if (name = theName('dir'))\n\ window.open(\'!AZ?name=\'+name+\'&s-list=List\',\'_blank\');\n\ else\n\ alert(\'!AZ\');\n\ return false;\n\ }\n\ function dirTree() {\n\ if (name = theName('dir'))\n\ window.open(\'!AZ?name=\'+name+\'&s-tree=tree\',\'_blank\');\n\ else\n\ alert(\'!AZ\');\n\ return false;\n\ }\n\ function fileEdit() {\n\ var as = document.getElementById(\'fileas\').value;\n\ var prot = document.getElementById(\'fileprot\');\n\ prot = prot.options[prot.selectedIndex];\n\ if (prot) prot=prot.value; else prot = \'\';\n\ var id = document.getElementById(\'filename\');\n\ id = id.options[id.selectedIndex];\n\ if (id) var name = id.value; else var name = as;\n\ if (name.length)\n\ window.open(\'!AZ?name=\'+escape(name)+\'&as=\'+escape(as)+\'\ &protection=\'+escape(prot)+\'&s-edit=Edit\',\'_blank\');\n\ else\n\ alert(\'!AZ\');\n\ return false;\n\ }\n\ function fileView() {\n\ if (name = theName('file'))\n\ window.open(\'!AZ\'+name,\'_blank\');\n\ else\n\ alert(\'!AZ\');\n\ return false;\n\ }\n\ // -->\n\ </script>\n\ </head>\n\ !AZ\n\ <div class=\"wasd\">\n\ <h2>!AZ !AZ</h2>\n\ \ <p><table class=\"ctgry\">\n\ \ <tr><th class=\"ctttl\" style=\"font-size:125%;\" colspan=\"2\">\n\ <a href=\"!&%AZ\">!&;&[AZ</a>\n\ !AZ\n\ <a class=\"abttn\" target=\"_blank\" href=\"!&;AZ\" \ style=\"margin-left:2em;\">!&;AZ</a>\n\ </th></tr>\n\ \ <tr>\n\ \ <td style=\"padding:0.5em 0 0.5em 1em;\">\n\ \ <form id=\"navForm\" METHOD=\"GET\" action=\"!&%AZ!&%AZ\">\n\ <table class=\"lftlft\">\n\ \ <tr><th class=\"sbttl\" colspan=\"2\">!AZ</th></tr>\n\ \ <tr><td>\n\ <select size=\"!UL\" id=\"dirname\" name=\"name\" \ style=\"min-width:20em;max-width:40em;\">\n\ <option value=\".\" selected> ./\n\ !AZ"; int status; unsigned short Length; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr; char LocationFile [ODS_MAX_FILE_NAME_LENGTH+1], LocationUpd [ODS_MAX_FILE_NAME_LENGTH+1], Scratch [256]; REQUEST_AST AstFunction; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdNavigateBegin()"); tkptr = rqptr->UpdTaskPtr; if (WATCHPNT(rqptr) && WATCH_CATEGORY(WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE navigate !AZ", rqptr->ParseOds.ExpFileName); /************/ /* navigate */ /************/ if (CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength) { /* the VMS security profile allows access, why further prohibit it? */ status = SS$_NORMAL; } else { /* ensure we can read these directory listing "control" files */ sys$setprv (1, &SysPrvMask, 0, 0); if (VMSok (status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirHiddenFileName))) status = RMS$_DNF; else if ((Config.cfDir.AccessSelective || rqptr->rqPathSet.DirAccessSelective) && !rqptr->rqPathSet.DirAccess) status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirBrowsableFileName); else if (VMSok (status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirNoWildFileName))) status = RMS$_WLD; else status = SS$_NORMAL; sys$setprv (0, &SysPrvMask, 0, 0); } if (VMSnok (status)) { /* give some "disinformation" ;^) */ if (status == RMS$_FNF) status = RMS$_DNF; rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /* check if we can see its subdirectories, if not then straight to files */ sys$setprv (1, &SysPrvMask, 0, 0); if (VMSnok (status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirNosFileName))) status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirNopsFileName); sys$setprv (0, &SysPrvMask, 0, 0); if (VMSnok(status)) { AstFunction = &UpdNavigateSearchDirs; /***************************/ /* set up directory search */ /***************************/ AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_READ); OdsParse (&tkptr->SearchOds, rqptr->ParseOds.ExpFileName, rqptr->ParseOds.NamNamePtr - rqptr->ParseOds.ExpFileName, "*.DIR;", 6, 0, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } } else AstFunction = &UpdNavigateBeginFiles; /**************/ /* begin page */ /**************/ cptr = MsgFor(rqptr,MSG_UPD_NAVIGATE); zptr = (sptr = tkptr->MsgString) + sizeof(tkptr->MsgString); while (*cptr && sptr < zptr) { /* don't need any extraneous linefeeds from this long string */ if (*cptr == '\n') cptr++; else *sptr++ = *cptr++; } if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; FaoToBuffer (LocationFile, sizeof(LocationFile), 0, "!AZ//!AZ!&%AZ", rqptr->ServicePtr->RequestSchemeNamePtr, rqptr->ServicePtr->ServerHostPort, rqptr->rqHeader.PathInfoPtr); FaoToBuffer (LocationUpd, sizeof(LocationUpd), 0, "!AZ//!AZ!AZ!&%AZ", rqptr->ServicePtr->RequestSchemeNamePtr, rqptr->ServicePtr->ServerHostPort, rqptr->ScriptName, rqptr->rqHeader.PathInfoPtr); rqptr->rqResponse.PreExpired = PRE_EXPIRE_UPD; ResponseHeader200 (rqptr, "text/html", NULL); vecptr = FaoVector; *vecptr++ = WASD_DOCTYPE; *vecptr++ = HtmlMetaInfo (rqptr, rqptr->ParseOds.ExpFileName); *vecptr++ = AdminWasdCss (); if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "<link rel=\"stylesheet\" type=\"text/css\" href=\"!AZ\">\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; /* "Update" */ *vecptr++ = cptr = tkptr->MsgString; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = LocationUpd; *vecptr++ = MsgFor(rqptr,MSG_UPD_FILENAME); *vecptr++ = LocationUpd; *vecptr++ = MsgFor(rqptr,MSG_UPD_FILENAME); *vecptr++ = LocationUpd; *vecptr++ = MsgFor(rqptr,MSG_UPD_FILENAME); *vecptr++ = LocationFile; *vecptr++ = MsgFor(rqptr,MSG_UPD_FILENAME); *vecptr++ = ADMIN_BODY_TAG; /* "Update" again */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = rqptr->PathOds; *vecptr++ = rqptr->rqHeader.PathInfoPtr; #ifdef ODS_EXTENDED if (OdsExtended && (!rqptr->PathOds || rqptr->PathOds == MAPURL_PATH_ODS_2)) *vecptr++ = " ODS-2"; else if (OdsExtended && rqptr->PathOds == MAPURL_PATH_ODS_5) *vecptr++ = " ODS-5"; else #endif /* ODS_EXTENDED */ if (rqptr->PathOds == MAPURL_PATH_ODS_ADS) *vecptr++ = " ODS-ADS"; else if (rqptr->PathOds == MAPURL_PATH_ODS_PWK) *vecptr++ = " ODS-PWK"; else if (rqptr->PathOds == MAPURL_PATH_ODS_SMB) *vecptr++ = " ODS-SMB"; else if (rqptr->PathOds == MAPURL_PATH_ODS_SRI) *vecptr++ = " ODS-SRI"; else if (rqptr->PathOds) *vecptr++ = "ODS-?"; else *vecptr++ = ""; *vecptr++ = UPD_HELP_PATH; /* ["help"] */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* form action */ *vecptr++ = rqptr->ScriptName; *vecptr++ = tkptr->PathInfoDir; /* "subdirectories" title */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* save the current position for use in later parts of the page */ tkptr->MsgStringPtr = cptr; *vecptr++ = NAVIGATE_SIZE; /* if there is a parent directory */ sptr = (cptr = tkptr->PathInfoDir) + tkptr->PathInfoDirLength; while (sptr > cptr && *sptr != '/') sptr--; if (sptr > cptr && *sptr == '/') sptr--; while (sptr > cptr && *sptr != '/') sptr--; if (sptr > cptr && *sptr == '/') sptr++; if (sptr == cptr) *vecptr++ = ""; else *vecptr++ = "<option value=\"..\" ondblclick=\"dirDblClick()\">../\n"; status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } tkptr->FileCount = 0; NetWritePartFlush (rqptr, AstFunction); } /*****************************************************************************/ /* (AST) function to invoke another sys$search() call when listing directories. */ UpdNavigateSearchDirs (REQUEST_STRUCT *rqptr) { UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdNavigateSearchDirs() !&F", &UpdNavigateSearchDirs); /* get the pointer to the task structure */ tkptr = rqptr->UpdTaskPtr; AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); OdsSearch (&tkptr->SearchOds, &UpdNavigateDirs, rqptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* AST completion routine called each time sys$search() completes. It will either point to another file name found or have "no more files found" status (or an error!). */ void UpdNavigateDirs (REQUEST_STRUCT *rqptr) { int status; unsigned long FaoVector [8]; unsigned long *vecptr; char ch; char *cptr, *sptr; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdNavigateDirs() !&F sts:!&X stv:!&X", &UpdNavigateDirs, rqptr->UpdTaskPtr->SearchOds.Fab.fab$l_sts, rqptr->UpdTaskPtr->SearchOds.Fab.fab$l_stv); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { UpdEnd (rqptr); return; } tkptr = rqptr->UpdTaskPtr; if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { /* if its a search list treat directory not found as if file not found */ if ((tkptr->SearchOds.Nam_fnb & NAM$M_SEARCH_LIST) && status == RMS$_DNF) status = RMS$_FNF; if (status == RMS$_FNF || status == RMS$_NMF) { /* end of directory search, list files */ tkptr->SearchOds.ParseInUse = false; UpdNavigateBeginFiles (rqptr); return; } /* sys$search() error */ rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->SearchOds.NamDevicePtr; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /* check if the .DIR is really a directory */ status = OdsReallyADir (rqptr, &tkptr->SearchOds); if (VMSnok (status)) { UpdNavigateSearchDirs (rqptr); return; } /* terminate following the last character in the version number */ tkptr->SearchOds.NamVersionPtr[tkptr->SearchOds.NamVersionLength] = '\0'; /* not interested in master file directories :^) */ if (MATCH7 (tkptr->SearchOds.NamNamePtr, "000000.")) { UpdNavigateSearchDirs (rqptr); return; } tkptr->SearchOds.NamNamePtr[-1] = '.'; tkptr->SearchOds.NamTypePtr[0] = ']'; ch = tkptr->SearchOds.NamTypePtr[1]; tkptr->SearchOds.NamTypePtr[1] = '\0'; if (CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength) { /* the VMS security profile allows access, why further prohibit it? */ status = SS$_NORMAL; } else { /* ensure we can read these directory listing "control" files */ sys$setprv (1, &SysPrvMask, 0, 0); if (VMSok (status = OdsFileExists (tkptr->SearchOds.ResFileName, DirHiddenFileName))) status = RMS$_DNF; else if ((Config.cfDir.AccessSelective || rqptr->rqPathSet.DirAccessSelective) && !rqptr->rqPathSet.DirAccess) status = OdsFileExists (tkptr->SearchOds.ResFileName, DirBrowsableFileName); else status = SS$_NORMAL; sys$setprv (0, &SysPrvMask, 0, 0); } tkptr->SearchOds.NamNamePtr[-1] = ']'; tkptr->SearchOds.NamTypePtr[0] = '.'; tkptr->SearchOds.NamTypePtr[1] = ch; if (VMSnok (status)) { /* no, it shouldn't/couldn't be accessed */ UpdNavigateSearchDirs (rqptr); return; } tkptr->FileCount++; tkptr->SearchOds.NamTypePtr[0] = '\0'; vecptr = FaoVector; *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->SearchOds.NamNamePtr, *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->SearchOds.NamNamePtr, status = FaolToNet (rqptr, "<option value=\"!&;&[AZ\" ondblclick=\"dirDblClick()\">!&;&[AZ\n", &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); tkptr->SearchOds.NamTypePtr[0] = '.'; NetWritePartFlush (rqptr, &UpdNavigateSearchDirs); } /*****************************************************************************/ /* End directory search. Begin file search. */ void UpdNavigateBeginFiles (REQUEST_STRUCT *rqptr) { static char EndSelectFao [] = "</select>\n\ <div style=\"padding:0.3em;\">\n\ <sup>1.</sup> <i>!AZ</i>\n\ <br><sup>2.</sup> <i>!AZ</i>\n\ </div>\n\ <input type=\"text\" id=\"diras\" name=\"as\" size=\"20\">\n\ <br>!AZ\ <br><input type=reset value=\"!AZ\">\n\ </td><td>\n\ <table class=\"lftlft\">\n\ <tr>\ <td><input type=\"submit\" name=\"s-goto\" id=\"s-goto\" value=\"!AZ\"></td>\ <td><sup>1.</sup></td></tr>\n\ <tr><td>\ <input type=\"submit\" name=\"s-list\" value=\"!AZ\" \ style=\"margin-right:0;\">\ <input type=\"submit\" style=\"min-width:1em;\" value=\"^\" \ onclick=\"return dirList()\" \ style=\"margin-left:0;\">\ </td>\ <td><sup>1.</sup></td></tr>\n\ <tr><td>\ <input type=\"submit\" name=\"s-tree\" value=\"!AZ\" \ style=\"margin-right:0;\">\ <input type=\"submit\" style=\"min-width:1em;\" name=\"s-tree^\" value=\"^\" \ onclick=\"return dirTree()\" \ style=\"margin-left:0;\">\ </td>\ <td><sup>1.</sup></td></tr>\n\ <tr><td>\ <input type=\"submit\" name=\"s-mkdir\" value=\"!AZ\"></td>\ <td><sup>2.</sup></td></tr>\n\ <tr>\ <td><input type=\"submit\" name=\"s-dirprotect\" value=\"!AZ\"></td>\ <td><sup>1./2.</sup></td></tr>\n\ <tr><td>\ <input type=\"submit\" name=\"s-rmdir\" value=\"!AZ\"></td>\ <td><sup>1.</sup></td></tr>\n\ <tr><td><input type=\"submit\" value=\"!AZ\" \ onclick=\"location.reload(true);return false\"></td>\ <td style=\"font-size:170%;position:relative;\ top:-0.3em;left:-0.2em;\">!AZ</td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n\ </form>\n\ </td>\n\ \ <td style=\"padding:0.5em 0 0.5em 1em;\">\n\ \ <form method=\"GET\" action=\"!&%AZ!&%AZ\">\n\ <table class=\"lftlft\">\n\ \ <tr><th class=\"sbttl\" colspan=\"2\">!AZ</th></tr>\n\ \ <tr><td>\n\ <select size=\"!UL\" id=\"filename\" name=\"name\" \ style=\"min-width:20em;max-width:40em;\">\n"; int status; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr, *MsgFilesPtr; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdNavigateBeginFiles()"); tkptr = rqptr->UpdTaskPtr; AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_READ); OdsParse (&tkptr->SearchOds, rqptr->ParseOds.ExpFileName, rqptr->ParseOds.NamVersionPtr - rqptr->ParseOds.ExpFileName, "*.*;0", 5, 0, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /**************/ /* begin page */ /**************/ vecptr = FaoVector; /* retrieve the previously saved position in the string */ cptr = tkptr->MsgStringPtr; /* "files" (for historical reasons is here) */ MsgFilesPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; if (tkptr->FileCount) { /* "select from list" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* skip over "none available" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; } else { /* skip over "select from list" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; /* "none available" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; } /* "enter name" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* file protection */ *vecptr++ = tkptr->ProtectionList; /* reset */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* goto */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* list */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* tree */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* create */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* protection */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* delete */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* save the current position for use in later parts of the page */ tkptr->MsgStringPtr = cptr; *vecptr++ = REFRESH_SYMBOL; *vecptr++ = REFRESH_SYMBOL; /* form action */ *vecptr++ = rqptr->ScriptName; *vecptr++ = tkptr->PathInfoDir; /* "files" title */ *vecptr++ = MsgFilesPtr; *vecptr++ = NAVIGATE_SIZE; status = FaolToNet (rqptr, EndSelectFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } tkptr->FileCount = 0; NetWritePartFlush (rqptr, &UpdNavigateSearchFiles); } /*****************************************************************************/ /* (AST) function to invoke another sys$search() call when listing Files. */ void UpdNavigateSearchFiles (REQUEST_STRUCT *rqptr) { UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdNavigateSearchFiles() !&F", &UpdNavigateSearchFiles); /* get the pointer to the task structure */ tkptr = rqptr->UpdTaskPtr; AuthAccessEnable (rqptr, tkptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); OdsSearch (&tkptr->SearchOds, &UpdNavigateFiles, rqptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* AST completion routine called each time sys$search() completes. It will either point to another file name found or have "no more files found" status (or an error!). */ UpdNavigateFiles (REQUEST_STRUCT *rqptr) { int status; unsigned long FaoVector [8]; unsigned long *vecptr; char *cptr, *sptr; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdNavigateFiles() !&F sts:!&X stv:!&X", &UpdNavigateFiles, rqptr->UpdTaskPtr->SearchOds.Fab.fab$l_sts, rqptr->UpdTaskPtr->SearchOds.Fab.fab$l_stv); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { UpdEnd (rqptr); return; } tkptr = rqptr->UpdTaskPtr; if (VMSnok (status = tkptr->SearchOds.Fab.fab$l_sts)) { if (status == RMS$_FNF || status == RMS$_NMF) { /* end of file search */ tkptr->SearchOds.ParseInUse = false; UpdNavigateEnd (rqptr); return; } /* sys$search() error */ rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->SearchOds.NamDevicePtr; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /* terminate following the last character in the version number */ tkptr->SearchOds.NamVersionPtr[tkptr->SearchOds.NamVersionLength] = '\0'; if (MATCH5 (tkptr->SearchOds.NamTypePtr, ".DIR;") || MATCH5 (tkptr->SearchOds.NamTypePtr, ".dir;")) { /* it has a dot-dir type but is it really a directory file? */ status = OdsReallyADir (rqptr, &tkptr->SearchOds); if (VMSok (status)) { /* already have directories */ UpdNavigateSearchFiles (rqptr); return; } } /* in true Unix-style "hidden" files do not appear (those beginning ".") */ if (SAME1(tkptr->SearchOds.NamNamePtr, '.') || SAME2(tkptr->SearchOds.NamNamePtr, '^.')) { /* except in demo mode or to VMS authenticated and profiled requests */ if (!(CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength)) { if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, ".FILE (hidden)"); UpdNavigateSearchFiles (rqptr); return; } } /* specially check permissions for each file! */ status = AuthAccessReadCheck (rqptr, tkptr->SearchOds.ResFileName, tkptr->SearchOds.ResFileNameLength); if (VMSnok (status)) { if (status == SS$_NOPRIV) { /* does not have access */ UpdNavigateSearchFiles (rqptr); return; } /* error reported by access check */ UpdEnd (rqptr); return; } tkptr->FileCount++; tkptr->SearchOds.NamVersionPtr[0] = '\0'; vecptr = FaoVector; *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->SearchOds.NamNamePtr, *vecptr++ = rqptr->PathOds; *vecptr++ = tkptr->SearchOds.NamNamePtr, status = FaolToNet (rqptr, "<option value=\"!&;&[AZ\" ondblclick=\"fileDblClick()\">!&;&[AZ\n", &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); tkptr->SearchOds.NamVersionPtr[0] = ';'; NetWritePartFlush (rqptr, &UpdNavigateSearchFiles); } /*****************************************************************************/ /* End file search and end of navigation functions. */ void UpdNavigateEnd (REQUEST_STRUCT *rqptr) { static char EndSelectFao [] = "</select>\n\ <div style=\"padding:0.3em;\">\n\ <sup>1.</sup> <i>!AZ</i>\n\ <br><sup>2.</sup> <i>!AZ</i>\n\ </div>\n\ <input type=\"text\" id=\"fileas\" name=\"as\" size=\"20\">\n\ <br>!AZ\ <br><input type=reset value=\"!AZ\">\n\ </td><td>\n\ <table class=\"lftlft\">\n\ <tr><td>\ <input type=\"submit\" name=\"s-view\" id=\"s-view\" \ value=\"!AZ\" style=\"margin-right:0;\">\ <input type=\"submit\" style=\"min-width:1em;\" \ value=\"^\" id=\"s-view-open\" \ onclick=\"return fileView()\" \ style=\"margin-left:0;\">\ </td>\ <td><sup>1.</sup></td></tr>\n\ <tr><td>\ <input type=\"submit\" name=\"s-edit\" value=\"!AZ\" \ style=\"margin-right:0;\">\ <input type=\"submit\" style=\"min-width:1em;\" name=\"s-edit^\" value=\"^\" \ onclick=\"return fileEdit()\" \ style=\"margin-left:0;\">\ </td>\ <td><sup>1.[&2.]</sup></td></tr>\n" #ifdef UPD_CREATE "<tr><td>\ <input type=\"submit\" name=\"s-create\" value=\"!AZ\"></td>\ <td><sup>2.</sup></td></tr>\n" #endif /* UPD_CREATE */ #ifdef UPD_FILTER "<tr><td>\ <input type=\"submit\" name=\"s-filter\" value=\"!AZ\"></td>\ <td><sup>1.&2.</sup></td></tr>\n" #endif /* UPD_FILTER */ "<tr><td>\ <input type=\"submit\" name=\"s-filerename\" value=\"!AZ\">\ </td>\ <td><sup>1.&2.</sup></td></tr>\n\ <tr><td>\ <input type=\"submit\" name=\"s-copy\" value=\"!AZ\"></td>\ <td><sup>1.&2.</sup></td></tr>\n\ <tr><td>\ <input type=\"submit\" name=\"s-fileprotect\" value=\"!AZ\">\ </td>\ <td><sup>1./2.</sup></td></tr>\n\ <tr><td>\ <input type=\"submit\" name=\"s-delete\" value=\"!AZ\"></td>\ <td><sup>1./2.</sup></td></tr>\n\ <tr><td><input type=\"submit\" value=\"!AZ\" \ onclick=\"location.reload(true);return false\"></td>\n\ <td style=\"font-size:170%;position:relative;\ top:-0.3em;left:-0.2em;\">!AZ</td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n\ </form>\n\ \ <form method=\"POST\" action=\"!&%AZ\" enctype=\"multipart/form-data\">\n\ <p>\n\ <input type=\"submit\" value=\"!AZ\">\n\ !AZ <input type=\"text\" name=\"uploadfilename\" size=\"20\">\n\ <br> !AZ\ <br> !AZ <input type=\"file\" name=\"name\" size=\"20\">\n\ </form>\n\ </td>\n\ \ </tr>\n\ </table>\n\ \ </div>\n\ </body>\n\ </html>\n"; int status; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *MsgAsPtr, *MsgLocalFilePtr, *MsgUploadPtr; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdNavigateEnd()"); tkptr = rqptr->UpdTaskPtr; /* retrieve the previously saved position in the string */ cptr = tkptr->MsgStringPtr; /* for historical reasons "Upload", "As", "Local File" messages are here */ MsgUploadPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; MsgAsPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; MsgLocalFilePtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; vecptr = FaoVector; if (tkptr->FileCount) { /* "select from list" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* skip over "none available" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; } else { /* skip over "select from list" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; /* "none available" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; } /* "enter name/path" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* file protection */ *vecptr++ = tkptr->FileProtectionList; /* "reset" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* view */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* edit */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* create */ #ifdef UPD_CREATE *vecptr++ = cptr; #endif /* UPD_CREATE */ while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* filter */ #ifdef UPD_FILTER *vecptr++ = cptr; #endif /* UPD_FILTER */ while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* rename */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* copy */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* protection */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* delete */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = REFRESH_SYMBOL; *vecptr++ = REFRESH_SYMBOL; *vecptr++ = tkptr->PathInfoDir; *vecptr++ = MsgUploadPtr; *vecptr++ = MsgAsPtr; *vecptr++ = tkptr->ProtectionList; *vecptr++ = MsgLocalFilePtr; status = FaolToNet (rqptr, EndSelectFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); } UpdEnd (rqptr); } /*****************************************************************************/ /* Provide a directory tree display. Provides two types of tree. The first, an update tree, where tree node selection opens a new directory update page. Second, a general directory tree, where selecting a tree node behaves as any other directory URL (i.e. if a wildcard name.type;version is provided a listing is produced, if none then any home page existing in the directory is returned, else a directory listing, any query string supplied is reproduced in the tree link paths). */ void UpdTreeBegin (REQUEST_STRUCT *rqptr) { static char UpdateTreeFao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>Update !AZ</title>\n\ </head>\n\ !AZ\ <div class=\"wasd\">\n\ <h2>Update !AZ</h2>\n\ <hr size=\"2\" noshade><p>\n\ <pre> <a href=\"!&%AZ\"><b>!&;AZ</b></a>\n"; static char Tree1Fao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>!&@</title>\n\ </head>\n\ !&@\ !&@\ <div class=\"wasd\">\n"; static char Tree2Fao [] = "!AZ\ <pre><hr size=\"2\" noshade>\n\ <a href=\"!&%AZ!&??\r\r!AZ\"><b>!&;AZ</b></a>\n"; int status; unsigned short ShortLength; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr, *TreeOfPtr; char NameBuffer [ODS_MAX_FILE_NAME_LENGTH+1], PathBuffer [ODS_MAX_FILE_NAME_LENGTH+1]; REQUEST_AST AstFunction; UPD_TASK *tkptr; UPD_TREE *tnptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdTreeBegin()"); tkptr = rqptr->UpdTaskPtr; /* first check if the directory can be accessed */ if (CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength) { /* the VMS security profile allows access, why further prohibit it? */ status = SS$_NORMAL; } else { /* ensure we can read these directory listing "control" files */ sys$setprv (1, &SysPrvMask, 0, 0); if (VMSok (status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirHiddenFileName))) status = RMS$_DNF; else if ((Config.cfDir.AccessSelective || rqptr->rqPathSet.DirAccessSelective) && !rqptr->rqPathSet.DirAccess) status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirBrowsableFileName); else if (VMSok (status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirNoWildFileName))) status = RMS$_WLD; else status = SS$_NORMAL; sys$setprv (0, &SysPrvMask, 0, 0); } if (VMSnok (status)) { /* give some "disinformation" ;^) */ if (status == RMS$_FNF) status = RMS$_DNF; rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /* allocate heap memory for the initial tree structure */ tnptr = (UPD_TREE*)VmGetHeap (rqptr, sizeof(UPD_TREE)); tnptr->PrevTreeNodePtr = tnptr->NextTreeNodePtr = NULL; tkptr->TreeHeadPtr = tkptr->TreeNodePtr = tnptr; OdsStructInit (&tnptr->SearchOds, false); /* ensure we can read these directory listing "control" files */ sys$setprv (1, &SysPrvMask, 0, 0); status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirNosFileName); if (status = RMS$_FNF) status = OdsFileExists (rqptr->ParseOds.ExpFileName, DirNopsFileName); sys$setprv (0, &SysPrvMask, 0, 0); /* if we can see its subdirectories, if not then end */ if (status == RMS$_FNF) { AstFunction = &UpdTreeListDirs; /***************************/ /* set up directory search */ /***************************/ AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_READ); OdsParse (&tnptr->SearchOds, rqptr->ParseOds.ExpFileName, /* i.e. just the length of the dev:[dir] */ rqptr->ParseOds.NamNamePtr - rqptr->ParseOds.ExpFileName, "*.DIR;", 6, 0, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status = tnptr->SearchOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } } else AstFunction = &UpdTreeEnd; /**************/ /* begin page */ /**************/ /* just use 'PathBuffer' as scratch space */ strcpy (PathBuffer, tkptr->PathInfoDir); if (tkptr->FormatTreeLikeVms) { MapOdsUrlToVms (PathBuffer, NameBuffer, sizeof(NameBuffer), 0, rqptr->rqPathSet.MapEllipsis, rqptr->PathOds); if (!rqptr->PathOds || rqptr->PathOds == MAPURL_PATH_ODS_2) for (sptr = NameBuffer; *sptr; sptr++) *sptr = TOUP(*sptr); else for (sptr = NameBuffer; *sptr; sptr++); /* get the length of all but the last directory element */ while (sptr > NameBuffer && *sptr != '.' && *sptr != '[') sptr--; tkptr->TreeIndent = sptr - NameBuffer + 3; } else { vecptr = FaoVector; *vecptr++ = rqptr->PathOds; *vecptr++ = PathBuffer; FaolToBuffer (NameBuffer, sizeof(NameBuffer), &ShortLength, "!&[AZ", &FaoVector); /* get the length of all but the last directory element */ sptr = NameBuffer + ShortLength; if (sptr > NameBuffer) sptr--; while (sptr > NameBuffer && *sptr != '/') sptr--; if (sptr > NameBuffer) sptr--; while (sptr > NameBuffer && *sptr != '/') sptr--; tkptr->TreeIndent = sptr - NameBuffer + 3; } zptr = (sptr = PathBuffer) + sizeof(PathBuffer)-1; if (tkptr->UpdateTree) { cptr = rqptr->ScriptName; while (*cptr && sptr < zptr) *sptr++ = *cptr++; } cptr = tkptr->PathInfoDir; while (*cptr && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "!UL !&Z !&Z", tkptr->TreeIndent, PathBuffer, NameBuffer); /* "tree"s can have pre-expiry controlled from the query string */ ResponseHeader200 (rqptr, "text/html", NULL); vecptr = FaoVector; *vecptr++ = WASD_DOCTYPE; *vecptr++ = HtmlMetaInfo (rqptr, rqptr->ParseOds.ExpFileName); if (tkptr->UpdateTree) *vecptr++ = AdminWasdCss (); else *vecptr++ = ""; if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "<link rel=\"stylesheet\" type=\"text/css\" href=\"!AZ\">\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; if (tkptr->UpdateTree) { *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = ADMIN_BODY_TAG; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = PathBuffer; *vecptr++ = NameBuffer; status = FaolToNet (rqptr, UpdateTreeFao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); } else { TreeOfPtr = MsgFor(rqptr,MSG_DIR_TREE_OF); /* <title>..</title> */ if (tkptr->FormatTreeLikeVms) { *vecptr++ = "!AZ !&;AZ"; *vecptr++ = TreeOfPtr; *vecptr++ = NameBuffer; } else if (rqptr->rqPathSet.DirStyle == MAPURL_DIR_STYLE_HTDIR) { *vecptr++ = "//!AZ/!&;AZ"; if (rqptr->rqHeader.HostPtr && rqptr->rqHeader.HostPtr[0]) *vecptr++ = rqptr->rqHeader.HostPtr; else *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = NameBuffer; } else { *vecptr++ = "!AZ //!AZ!&;AZ"; *vecptr++ = TreeOfPtr; if (rqptr->rqHeader.HostPtr && rqptr->rqHeader.HostPtr[0]) *vecptr++ = rqptr->rqHeader.HostPtr; else *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = NameBuffer; } if (rqptr->rqPathSet.HtmlBodyTagPtr) { /* <body..> */ if (rqptr->rqPathSet.HtmlBodyTagPtr[0] == '<') *vecptr++ = "!AZ\n"; else *vecptr++ = "<body!&+AZ>\n"; *vecptr++ = rqptr->rqPathSet.HtmlBodyTagPtr; } else { *vecptr++ = "!AZ\n"; *vecptr++ = Config.cfDir.BodyTag; } if (rqptr->rqPathSet.HtmlHeaderPtr || rqptr->rqPathSet.HtmlHeaderTagPtr) { if (rqptr->rqPathSet.HtmlHeaderTagPtr && rqptr->rqPathSet.HtmlHeaderTagPtr[0] == '<') *vecptr++ = "!AZ\n!&/AZ"; else *vecptr++ = "<table class=\"lftlft\"><tr><td!&+AZ>\n!&/AZ"; *vecptr++ = rqptr->rqPathSet.HtmlHeaderTagPtr; *vecptr++ = rqptr->rqPathSet.HtmlHeaderPtr; } else *vecptr++ = ""; status = FaolToNet (rqptr, Tree1Fao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); UpdTreeOf (rqptr, TreeOfPtr, PathBuffer, NameBuffer); vecptr = FaoVector; if (rqptr->rqPathSet.HtmlHeaderPtr || rqptr->rqPathSet.HtmlHeaderTagPtr) *vecptr++ = "</td></tr></table>\n"; else *vecptr++ = ""; *vecptr++ = PathBuffer; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr[0] : 0; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr : ""; *vecptr++ = NameBuffer; status = FaolToNet (rqptr, Tree2Fao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); } tkptr->TreeLevel = 0; NetWriteFullFlush (rqptr, AstFunction); } /*****************************************************************************/ /* Provide the "Index of" page heading in any of the post-v8.2, traditional WASD, or the "ABI" styles. */ int UpdTreeOf ( REQUEST_STRUCT *rqptr, char *TreeOfPtr, char *PathBuffer, char *NameBuffer ) { /* allows as directory nesting of up to 64 (should be enough ;^) */ static char DotDotSlash64 [] = "<a href=\"./\ ../../../../../../../../../../../../../../../../\ ../../../../../../../../../../../../../../../../\ ../../../../../../../../../../../../../../../../\ ../../../../../../../../../../../../../../../../"; int cnt, status, SlashCount; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr, *FinalSlashPtr; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdTreeOf() !&Z !&Z !&Z", TreeOfPtr, PathBuffer, NameBuffer); /* get the pointer to the task structure */ tkptr = rqptr->UpdTaskPtr; if (rqptr->rqPathSet.DirStyle == MAPURL_DIR_STYLE_ORIGINAL) { /**************************/ /* traditional WASD style */ /**************************/ vecptr = &FaoVector; *vecptr++ = TreeOfPtr; *vecptr++ = PathBuffer; status = FaolToNet (rqptr, "<h2>!AZ !&;&_AZ</h2>\n", &FaoVector); return (status); } /****************/ /* other styles */ /****************/ /* calculate the number of directory elements */ SlashCount = 0; FinalSlashPtr = ""; for (cptr = PathBuffer; *cptr; cptr++) { if (*cptr == '/') { SlashCount++; FinalSlashPtr = cptr; } } if (SlashCount > 64) return (SS$_BUGCHECK); if (*FinalSlashPtr) FinalSlashPtr++; if (tkptr->FormatTreeLikeVms) { vecptr = &FaoVector; *vecptr++ = TreeOfPtr; status = FaolToNet (rqptr, "<h3>!AZ ", &FaoVector); if (VMSnok (status)) return (status); cptr = NameBuffer; } else { vecptr = &FaoVector; if (rqptr->rqPathSet.DirStyle == MAPURL_DIR_STYLE_HTDIR) { /* ABI's style begins with the server name as a 'root' anchor */ *vecptr++ = rqptr->ScriptName; *vecptr++ = FinalSlashPtr; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr[0] : 0; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr : ""; if (rqptr->rqHeader.HostPtr && rqptr->rqHeader.HostPtr[0]) *vecptr++ = rqptr->rqHeader.HostPtr; else *vecptr++ = rqptr->ServicePtr->ServerHostPort; status = FaolToNet (rqptr, "<h3><a href=\"!AZ/!AZ!&??\r\r!AZ\">//!AZ/</a>", &FaoVector); } else { /* WASD style provides an "Tree of" heading */ *vecptr++ = TreeOfPtr; *vecptr++ = rqptr->ScriptName; *vecptr++ = FinalSlashPtr; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr[0] : 0; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr : ""; if (rqptr->rqHeader.HostPtr && rqptr->rqHeader.HostPtr[0]) *vecptr++ = rqptr->rqHeader.HostPtr; else *vecptr++ = rqptr->ServicePtr->ServerHostPort; status = FaolToNet (rqptr, "<h3>!AZ //<a href=\"!AZ/!AZ!&??\r\r!AZ\">!AZ</a>/", &FaoVector); } if (VMSnok (status)) return (status); cptr = PathBuffer; } /* provide a self-relative (../) anchor for each directory element */ if (SlashCount) SlashCount--; while (SlashCount-- > 0) { vecptr = &FaoVector; *vecptr++ = 11 + (SlashCount * 3); *vecptr++ = DotDotSlash64; *vecptr++ = FinalSlashPtr; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr[0] : 0; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr : ""; if (tkptr->FormatTreeLikeVms) { /* VMS format, parse based on VMS directory delimiting characters */ while (*cptr == '.' || *cptr == ':' || *cptr == '[' || *cptr == ']') cptr++; for (sptr = cptr; *sptr && *sptr != '.' && *sptr != ':' && *sptr != ']'; sptr++) if (*sptr == '^') sptr++; *vecptr++ = sptr - cptr; *vecptr++ = cptr; if (*sptr == ':') *vecptr++ = 2; else *vecptr++ = 1; *vecptr++ = sptr; } else { /* URL format, parse based on delimiting slashes */ if (*cptr == '/') cptr++; for (sptr = cptr; *sptr && *sptr != '/'; sptr++); if (rqptr->rqPathSet.DirStyle == MAPURL_DIR_STYLE_HTDIR) { /* ABI's style, trailing slashes are part of the link */ if (*sptr) sptr++; *vecptr++ = sptr - cptr; *vecptr++ = cptr; *vecptr++ = 0; *vecptr++ = ""; } else { /* WASD style, trailing slashes are not part of the link */ *vecptr++ = sptr - cptr; *vecptr++ = cptr; *vecptr++ = 1; *vecptr++ = sptr; } } if (VMSnok (status)) return (status); status = FaolToNet (rqptr, "!#AZ!AZ!&??\r\r!&;AZ\">!#AZ</a>!#AZ", &FaoVector); cptr = sptr; } if (!PathBuffer && rqptr->rqPathSet.DirStyle == MAPURL_DIR_STYLE_HTDIR) { /* ABI's style, 'file' name and type element as an anchor */ if (*cptr == '/') cptr++; vecptr = &FaoVector; *vecptr++ = cptr; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr[0] : 0; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr : ""; *vecptr++ = cptr; status = FaolToNet (rqptr, "<a href=\"!AZ!&??\r\n!AZ\">!AZ</a></h3>\n", &FaoVector); } else { /* WASD style, URL or VMS format, 'file' name and type just displayed */ if (tkptr->FormatTreeLikeVms) while (*cptr == ':' || *cptr == '[' || *cptr == '.' || *cptr == ']') cptr++; else if (*cptr == '/') cptr++; vecptr = &FaoVector; *vecptr++ = cptr; status = FaolToNet (rqptr, "!AZ</h3>\n", &FaoVector); } return (status); } /*****************************************************************************/ /* (AST) function to invoke another sys$search() call when listing directories. */ void UpdTreeListDirs (REQUEST_STRUCT *rqptr) { UPD_TREE *tnptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdTreeListDirs() !&F", &UpdTreeListDirs); /* get the pointer to the tree structure */ tnptr = rqptr->UpdTaskPtr->TreeNodePtr; AuthAccessEnable (rqptr, tnptr->SearchOds.ExpFileName, AUTH_ACCESS_READ); OdsSearch (&tnptr->SearchOds, &UpdTreeDirs, rqptr); AuthAccessEnable (rqptr, 0, 0); } /*****************************************************************************/ /* AST completion routine called each time sys$search() completes. It will either point to another dir name found or have "no more files found" status (or an error!). */ void UpdTreeDirs (REQUEST_STRUCT *rqptr) { int status, cnt; unsigned long FaoVector [32]; unsigned long *vecptr; char ch; char *cptr, *sptr, *tptr, *zptr; char Buffer [2048], NameBuffer [ODS_MAX_FILE_NAME_LENGTH+64+1], PathBuffer [ODS_MAX_FILE_NAME_LENGTH+64+1], NestingBuffer [512]; UPD_TASK *tkptr; UPD_TREE *tnptr, *tmptnptr, *NextTreeNodePtr, *PrevTreeNodePtr; /*********/ /* begin */ /*********/ #if WATCH_MOD HttpdCheckPriv (FI_LI); #endif /* WATCH_MOD */ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdTreeDirs() !&F sts:!&X stv:!&X", &UpdTreeDirs, rqptr->UpdTaskPtr->SearchOds.Fab.fab$l_sts, rqptr->UpdTaskPtr->SearchOds.Fab.fab$l_stv); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { UpdTreeEnd (rqptr); return; } tkptr = rqptr->UpdTaskPtr; tnptr = tkptr->TreeNodePtr; if (VMSnok (status = tnptr->SearchOds.Fab.fab$l_sts)) { if ((status == SS$_NOPRIV || status == RMS$_PRV) && Config.cfDir.NoPrivIgnore) { /* protection violation that we're configured to ignore */ tkptr->TreeLevel--; if (tnptr->PrevTreeNodePtr) { tkptr->TreeNodePtr = tnptr->PrevTreeNodePtr; UpdTreeListDirs (rqptr); } else UpdTreeEnd (rqptr); return; } if (status == RMS$_FNF || status == RMS$_NMF) { /* end of directory search, nest back one level or end */ tnptr->SearchOds.ParseInUse = false; tkptr->TreeLevel--; if (tnptr->PrevTreeNodePtr) { tkptr->TreeNodePtr = tnptr->PrevTreeNodePtr; UpdTreeListDirs (rqptr); } else UpdTreeEnd (rqptr); return; } /* sys$search() error */ rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = tnptr->SearchOds.NamDevicePtr; ErrorVmsStatus (rqptr, status, FI_LI); UpdTreeEnd (rqptr); return; } /* check if the .DIR is really a directory */ status = OdsReallyADir (rqptr, &tnptr->SearchOds); if (VMSnok (status)) { UpdTreeListDirs (rqptr); return; } /* terminate following the last character in the version number */ tnptr->SearchOds.NamVersionPtr[tnptr->SearchOds.NamVersionLength] = '\0'; if (MATCH7 (tnptr->SearchOds.NamNamePtr, "000000.")) { /* not interested in master file directories :^) */ UpdTreeListDirs (rqptr); return; } /****************************************/ /* check permissions for each directory */ /****************************************/ status = AuthAccessReadCheck (rqptr, tnptr->SearchOds.ResFileName, tnptr->SearchOds.ResFileNameLength); if (VMSnok (status)) { if (status == SS$_NOPRIV) { /* does not have access, as if it didn't exist! */ UpdTreeListDirs (rqptr); return; } UpdEnd (rqptr); return; } /************/ /* continue */ /************/ /* first check if the directory can be accessed */ tnptr->SearchOds.NamNamePtr[-1] = '.'; tnptr->SearchOds.NamTypePtr[0] = ']'; ch = tnptr->SearchOds.NamTypePtr[1]; tnptr->SearchOds.NamTypePtr[1] = '\0'; if (CliDemo || rqptr->rqAuth.SkelKeyAuthenticated || rqptr->rqAuth.VmsUserProfileLength) { /* the VMS security profile allows access, why further prohibit it? */ status = SS$_NORMAL; } else { /* ensure we can read these directory listing "control" files */ sys$setprv (1, &SysPrvMask, 0, 0); if (VMSok (status = OdsFileExists (tnptr->SearchOds.ResFileName, DirHiddenFileName))) status = RMS$_DNF; else if ((Config.cfDir.AccessSelective || rqptr->rqPathSet.DirAccessSelective) && !rqptr->rqPathSet.DirAccess) status = OdsFileExists (tnptr->SearchOds.ResFileName, DirBrowsableFileName); else status = SS$_NORMAL; sys$setprv (0, &SysPrvMask, 0, 0); } tnptr->SearchOds.NamNamePtr[-1] = ']'; tnptr->SearchOds.NamTypePtr[0] = '.'; tnptr->SearchOds.NamTypePtr[1] = ch; if (VMSnok (status)) { /* no, it can't be accessed */ UpdTreeListDirs (rqptr); return; } /*********************/ /* new level of tree */ /*********************/ if (tnptr->NextTreeNodePtr) { /* reuse previously allocated structure */ tnptr = tnptr->NextTreeNodePtr; NextTreeNodePtr = tnptr->NextTreeNodePtr; PrevTreeNodePtr = tnptr->PrevTreeNodePtr; memset (tnptr, 0, sizeof(UPD_TREE)); tnptr->NextTreeNodePtr = NextTreeNodePtr; tnptr->PrevTreeNodePtr = PrevTreeNodePtr; } else { /* allocate heap memory for the new (nested) tree task structure */ tnptr = (UPD_TREE*)VmGetHeap (rqptr, sizeof(UPD_TREE)); tnptr->PrevTreeNodePtr = tkptr->TreeNodePtr; tnptr->PrevTreeNodePtr->NextTreeNodePtr = tnptr; tnptr->NextTreeNodePtr = NULL; OdsStructInit (&tnptr->SearchOds, false); } tkptr->TreeNodePtr = tnptr; tkptr->TreeLevel++; sptr = tnptr->FileName; for (cptr = tnptr->PrevTreeNodePtr->SearchOds.ResFileName; cptr < tnptr->PrevTreeNodePtr->SearchOds.NamNamePtr; *sptr++ = *cptr++); sptr[-1] = '.'; while (cptr < tnptr->PrevTreeNodePtr->SearchOds.NamTypePtr) *sptr++ = *cptr++; *sptr++ = ']'; *sptr = '\0'; tnptr->FileNameLength = sptr - tnptr->FileName; /***************************/ /* set up directory search */ /***************************/ AuthAccessEnable (rqptr, tnptr->FileName, AUTH_ACCESS_READ); OdsParse (&tnptr->SearchOds, tnptr->FileName, tnptr->FileNameLength, "*.DIR;", 6, 0, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status = tnptr->SearchOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = tnptr->FileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /**************************/ /* display this directory */ /**************************/ zptr = (sptr = NameBuffer) + sizeof(NameBuffer)-1; cptr = tnptr->PrevTreeNodePtr->SearchOds.NamNamePtr; tptr = tnptr->PrevTreeNodePtr->SearchOds.NamTypePtr; while (*cptr && cptr < tptr && sptr < zptr) *sptr++ = *cptr++; *sptr = '\0'; zptr = (sptr = PathBuffer) + sizeof(PathBuffer)-1; if (tkptr->UpdateTree) { cptr = rqptr->ScriptName; while (*cptr && sptr < zptr) *sptr++ = *cptr++; } cptr = tkptr->PathInfoDir; while (*cptr && sptr < zptr) *sptr++ = *cptr++; /* add the name of all the directories to the link path */ tmptnptr = tkptr->TreeHeadPtr; while (tmptnptr != tnptr) { cptr = tmptnptr->SearchOds.NamNamePtr; tptr = tmptnptr->SearchOds.NamTypePtr; if (rqptr->PathOdsExtended && tkptr->FormatTreeLikeVms) while (*cptr && cptr < tptr && sptr < zptr) *sptr++ = *cptr++; else while (*cptr && cptr < tptr && sptr < zptr) *sptr++ = TOLO(*cptr++); if (sptr < zptr) *sptr++ = '/'; tmptnptr = tmptnptr->NextTreeNodePtr; } *sptr = '\0'; /* indent tree diagram using spaces, '|' and '-' */ zptr = (sptr = NestingBuffer) + sizeof(NestingBuffer)-1; for (cnt = tkptr->TreeIndent; cnt && sptr < zptr; cnt--) *sptr++ = ' '; for (cnt = tkptr->TreeLevel-1; cnt && sptr < zptr; cnt--) for (cptr = "| "; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = "|---"; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; vecptr = FaoVector; *vecptr++ = NestingBuffer; *vecptr++ = "!&%&[AZ!&%&[AZ!&??\r\r!AZ"; *vecptr++ = rqptr->PathOds; *vecptr++ = PathBuffer; *vecptr++ = rqptr->PathOds; *vecptr++ = rqptr->ParseOds.NamNamePtr; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr[0] : 0; *vecptr++ = rqptr->rqHeader.QueryStringLength ? rqptr->rqHeader.QueryStringPtr : ""; if (tkptr->FormatTreeLikeVms) if (!rqptr->PathOds || rqptr->PathOds == MAPURL_PATH_ODS_2) *vecptr++ = "!&;&^AZ"; else *vecptr++ = "!&;AZ"; else { *vecptr++ = "!&;&[AZ"; *vecptr++ = rqptr->PathOds; } *vecptr++ = NameBuffer; status = FaolToNet (rqptr, "!AZ<a href=\"!&@\">!&@</a>\n", &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); FaolToNet (rqptr, "\n<font color=\"#ff0000\">[Error]</font>\n", NULL); } NetWritePartFlush (rqptr, &UpdTreeListDirs); } /*****************************************************************************/ /* */ void UpdTreeEnd (REQUEST_STRUCT *rqptr) { static char TreeEndFao [] = "\n<hr size=\"2\" noshade></pre>\n\ !&@\ </div>\n\ </body>\n\ </html>\n"; int status; unsigned long FaoVector [32]; unsigned long *vecptr; UPD_TASK *tkptr; UPD_TREE *tnptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdTreeEnd()"); /* get the pointer to the task structure */ tkptr = rqptr->UpdTaskPtr; /* get the pointer to the tree structure */ tnptr = tkptr->TreeNodePtr; while (tnptr->PrevTreeNodePtr) { /* ensure parse internal data structures are released */ OdsParseRelease (&tnptr->SearchOds); /* get any previous node */ tnptr = tnptr->PrevTreeNodePtr; } vecptr = &FaoVector; if (rqptr->rqPathSet.HtmlFooterPtr || rqptr->rqPathSet.HtmlFooterTagPtr) { if (rqptr->rqPathSet.HtmlFooterTagPtr && rqptr->rqPathSet.HtmlFooterTagPtr[0] == '<') *vecptr++ = "!AZ\n!&@"; else *vecptr++ = "<table class=\"lftlft\"><tr><td!&+AZ>\n!&@"; *vecptr++ = rqptr->rqPathSet.HtmlFooterTagPtr; *vecptr++ = "!&/AZ</td></tr></table>\n"; *vecptr++ = rqptr->rqPathSet.HtmlFooterPtr; } else *vecptr++ = ""; status = FaolToNet (rqptr, TreeEndFao, &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); UpdEnd (rqptr); } /*****************************************************************************/ /* Generate a file editing page. This comprises an HTTP response header. Open the file. This checks whether it is an update (file exists) or create (file does not exist). Generate an HTML page and the start of a text area widget. Then initiate the file records being read, to be included within the <textarea></textarea> tags. */ void UpdEditFileBegin ( REQUEST_STRUCT *rqptr, REQUEST_AST NextTaskFunction, char *AsNamePtr ) { static char ResponseFao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>!AZ !AZ</title>\n\ <script language=\"JavaScript\">\n\ <!!--\n\ function changeEditWindow() {\n\ ted = document.getElementById(\'textedit\');\n\ cxr = document.getElementById(\"cxr\");\n\ cxrval = document.getElementById(\"cxr\").value;\n\ xpos = cxrval.indexOf(\'x\');\n\ ted.cols = parseInt(cxrval.substring(0,xpos));\n\ ted.rows = parseInt(cxrval.substring(xpos+1));\n\ return false;\n\ }\n\ // -->\n\ </script>\n\ </head>\n\ !AZ\n\ <div class=\"wasd\">\n\ <h2>!AZ !AZ</h2>\n\ !AZ\ !AZ\ <p>\n\ <form method=\"POST\" action=\"!&%AZ\">\n\ <input type=\"submit\" value=\"!AZ\">\n\ !&@\ <input type=\"reset\" value=\"!AZ\">\n\ !AZ\ <p>\n\ <textarea name=\"document\" id=\"textedit\" cols=\"!UL\" rows=\"!UL\">\ !AZ!AZ"; static $DESCRIPTOR (BytesFaoDsc, " (!UL bytes)\0"); static $DESCRIPTOR (DayDateFaoDsc, "!AZ, !20%D\0"); static $DESCRIPTOR (OutputFormatDsc, "|!WC, !DB-!MAAU-!Y4|!H04:!M0:!S0|"); static $DESCRIPTOR (NewFileFaoDsc, "<font color=\"#ff0000\">!AZ</font>\0"); BOOL ConfigEdit, FileExists; int status, ByteCount, RevDayOfWeek; unsigned long DateLength; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr, *ContentTypePtr, *HtmlTemplatePtr, *TitlePtr; char Bytes [32], DayDate [128], PostPath [ODS_MAX_FILE_NAME_LENGTH+1], FileSpec [ODS_MAX_FILE_NAME_LENGTH+1], SiteLogEntry [256], Source [1024]; UPD_TASK *tkptr; SERVICE_STRUCT *svptr; REQUEST_AST AstFunction; $DESCRIPTOR (BytesDsc, Bytes); $DESCRIPTOR (DayDateDsc, DayDate); /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdEditFileBegin() !&Z !&Z", AsNamePtr, rqptr->rqHeader.PathInfoPtr); /* this function CAN be called directly from the ADMIN.C module */ if (!(tkptr = rqptr->UpdTaskPtr)) { /* set up the task structure (only ever one per request!) */ rqptr->UpdTaskPtr = tkptr = (UPD_TASK*) VmGetHeap (rqptr, sizeof(UPD_TASK)); tkptr->NextTaskFunction = NextTaskFunction; if (!rqptr->AccountingDone++) InstanceGblSecIncrLong (&AccountingPtr->DoUpdateCount); } SiteLogEntry[0] = '\0'; ConfigEdit = true; cptr = rqptr->rqHeader.PathInfoPtr; if (strsame (cptr, ADMIN_REPORT_CONFIG, -1) || strsame (cptr, ADMIN_REVISE_CONFIG, -1)) TitlePtr = "<h3>Edit Server Configuration File</h3>\n"; else if (strsame (cptr, ADMIN_REPORT_MESSAGES, -1) || strsame (cptr, ADMIN_REVISE_MESSAGES, -1)) TitlePtr = "<h3>Edit Message File</h3>\n"; else if (strsame (cptr, ADMIN_REPORT_AUTH_PATHS, -1) || strsame (cptr, ADMIN_REVISE_AUTH_PATHS, -1)) TitlePtr = "<h3>Edit Path Authorization File</h3>\n"; else if (strsame (cptr, ADMIN_REVISE_MAPPING, -1) || strsame (cptr, ADMIN_REPORT_MAPPING, -1)) TitlePtr = "<h3>Edit Mapping Rule File</h3>\n"; else if (strsame (cptr, ADMIN_REPORT_SERVICES, -1) || strsame (cptr, ADMIN_REVISE_SERVICES, -1)) TitlePtr = "<h3>Edit Service Configuration File</h3>\n"; else if (strsame (cptr, ADMIN_REVISE_SITELOG, -1)) TitlePtr = "<h3>Edit Site Log</h3>\n"; else if (strsame (cptr, ADMIN_REVISE_SITELOG_ENTRY, -1)) { TitlePtr = "<h3>Edit Site Log</h3>\n"; vecptr = FaoVector; *vecptr++ = &rqptr->rqTime.BeginTime64; *vecptr++ = rqptr->RemoteUser; *vecptr++ = rqptr->rqAuth.RealmDescrPtr; *vecptr++ = rqptr->ClientPtr->Lookup.HostName; *vecptr++ = strlen(rqptr->RemoteUser) + strlen(rqptr->rqAuth.RealmDescrPtr) + strlen(rqptr->ClientPtr->Lookup.HostName) + 5; status = FaolToBuffer (SiteLogEntry, sizeof(SiteLogEntry), NULL, "+!79*-\n+ !17&W\n+ !&;AZ.\'!&;AZ\'@!&;AZ\n+!#*-\n\n\n\n", &FaoVector); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); } else if (strsame (cptr, ADMIN_REPORT_SSL_CA, -1) || strsame (cptr, ADMIN_REVISE_SSL_CA, -1)) TitlePtr = "<h3>Edit SSL CA Verification File</h3>\n"; else if (strsame (cptr, ADMIN_REVISE_HTL, sizeof(ADMIN_REVISE_HTL)-1)) TitlePtr = "<h3>Edit Authorization List</h3>\n"; else if (strsame (cptr, ADMIN_VS_REVISE_HTL, sizeof(ADMIN_VS_REVISE_HTL)-1)) TitlePtr = "<h3>Edit Authorization List</h3>\n"; else { ConfigEdit = false; TitlePtr = ""; } if (WATCHPNT(rqptr) && WATCH_CATEGORY(WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE edit !AZ", rqptr->ParseOds.ExpFileName); /**********************/ /* check content type */ /**********************/ /* from the request file parse */ if (rqptr->PathOds == MAPURL_PATH_ODS_ADS || rqptr->PathOds == MAPURL_PATH_ODS_SMB) cptr = MapOdsAdsFileType (rqptr->ParseOds.NamTypePtr); else if (rqptr->PathOds == MAPURL_PATH_ODS_SRI) cptr = MapOdsSriFileType (rqptr->ParseOds.NamTypePtr); else cptr = rqptr->ParseOds.NamTypePtr; ContentTypePtr = ConfigContentType (NULL, cptr); if (!ConfigSameContentType (ContentTypePtr, "text/", 5) && !strsame (cptr, HTL_FILE_TYPE, sizeof(HTL_FILE_TYPE)-1)) { rqptr->rqResponse.HttpStatus = 400; ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_NOT_TEXT_FILE), FI_LI); UpdEnd (rqptr); return; } /*************/ /* open file */ /*************/ AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_READ); OdsOpen (&tkptr->FileOds, rqptr->ParseOds.ExpFileName, rqptr->ParseOds.ExpFileNameLength, NULL, 0, 0, FAB$M_GET, FAB$M_SHRGET, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); status = tkptr->FileOds.Fab.fab$l_sts; if (VMSnok (status) && status != RMS$_FNF) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } if (status == RMS$_FNF) FileExists = tkptr->RecordFormatFixed = false; else { FileExists = true; if (tkptr->FileOds.Fab.fab$b_rfm == FAB$C_FIX || tkptr->FileOds.Fab.fab$b_rfm == FAB$C_UDF) tkptr->RecordFormatFixed = true; else tkptr->RecordFormatFixed = false; } if (VMSnok (status = OdsParseTerminate (&tkptr->FileOds))) { ErrorNoticed (rqptr, status, NULL, FI_LI); UpdEnd (rqptr); return; } if (FileExists) { /* record access block */ tkptr->FileOds.Rab = cc$rms_rab; tkptr->FileOds.Rab.rab$l_ctx = rqptr; tkptr->FileOds.Rab.rab$l_fab = &tkptr->FileOds.Fab; /* 2 buffers, transfer 16 blocks */ tkptr->FileOds.Rab.rab$b_mbc = 16; tkptr->FileOds.Rab.rab$b_mbf = 2; /* read ahead performance option */ tkptr->FileOds.Rab.rab$l_rop = RAB$M_RAH; tkptr->FileOds.Rab.rab$l_ubf = tkptr->EditBuffer; /* allow for two extra characters, a newline and a terminating null */ tkptr->FileOds.Rab.rab$w_usz = sizeof(tkptr->EditBuffer)-2; status = sys$connect (&tkptr->FileOds.Rab, 0, 0); if (VMSnok (status)) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } } /**************/ /* begin page */ /**************/ if (!ConfigEdit) { cptr = MsgFor(rqptr,MSG_UPD_EDIT); zptr = (sptr = tkptr->MsgString) + sizeof(tkptr->MsgString); while (*cptr && sptr < zptr) { /* don't need any extraneous linefeeds from this long string */ if (*cptr == '\n') cptr++; else *sptr++ = *cptr++; } if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; /* "Start at the very beginning, very good place to start ..." */ tkptr->MsgStringPtr = tkptr->MsgString; } if (FileExists) { if (ConfigEdit || NaturalLanguageEnglish) { lib$day_of_week (&tkptr->FileOds.XabDat.xab$q_rdt, &RevDayOfWeek); sys$fao (&DayDateFaoDsc, 0, &DayDateDsc, DayName[RevDayOfWeek], &tkptr->FileOds.XabDat.xab$q_rdt); } else { static unsigned long LibDateTimeContext = 0, LibOutputFormat = LIB$K_OUTPUT_FORMAT; if (!LibDateTimeContext) { /* initialize this particular date/time format */ if (VMSnok (status = lib$init_date_time_context (&LibDateTimeContext, &LibOutputFormat, &OutputFormatDsc))) { rqptr->rqResponse.ErrorTextPtr = "lib$init_date_time_context()"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } } if (VMSnok (status = lib$format_date_time (&DayDateDsc, &tkptr->FileOds.XabDat.xab$q_rdt, &LibDateTimeContext, &DateLength, 0))) { if (status != LIB$_ENGLUSED) { rqptr->rqResponse.ErrorTextPtr = "lib$format_date_time()"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } } DayDate[DateLength] = '\0'; } /* true for non-VAR record formats, almost true for those :^) */ if (tkptr->FileOds.XabFhc.xab$l_ebk) ByteCount = ((tkptr->FileOds.XabFhc.xab$l_ebk - 1) * 512) + tkptr->FileOds.XabFhc.xab$w_ffb; else ByteCount = tkptr->FileOds.XabFhc.xab$w_ffb; sys$fao (&BytesFaoDsc, 0, &BytesDsc, ByteCount); if (!ConfigEdit) { /* retrieve the previously saved position in the string */ cptr = tkptr->MsgStringPtr; /* step over "New Document" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; /* save the current position for use in later parts of the page */ tkptr->MsgStringPtr = cptr; } } else { if (ConfigEdit) sptr = "New File"; else { /* "New Document" */ sptr = cptr = tkptr->MsgStringPtr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* save the current position for use in later parts of the page */ tkptr->MsgStringPtr = cptr; } if (VMSnok (status = sys$fao (&NewFileFaoDsc, 0, &DayDateDsc, sptr))) strcpy (DayDate, "New File"); Bytes[0] = '\0'; } zptr = (sptr = PostPath) + sizeof(PostPath); if (ConfigEdit) cptr = rqptr->rqHeader.PathInfoPtr; else cptr = MapVmsPath (rqptr->ParseOds.ExpFileName, rqptr); /* remove any explicit version from the path to be POSTed */ while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (AsNamePtr[0] && sptr < zptr) { /* eliminate the trailing file name */ while (sptr > PostPath && *sptr != '/') sptr--; if (*sptr == '/') sptr++; /* add the destination file name */ for (cptr = AsNamePtr; *cptr && sptr < zptr; *sptr++ = *cptr++); } if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "!&Z", PostPath); if (ConfigEdit) { /**************************************************/ /* editing a configuration file from server admin */ /**************************************************/ vecptr = FaoVector; *vecptr++ = tkptr->FileOds.NamDevicePtr; *vecptr++ = PostPath; *vecptr++ = DayDate; if (AsNamePtr[0]) *vecptr++ = "Save As"; else if (FileExists) *vecptr++ = "Update"; else *vecptr++ = "Create"; status = FaolToBuffer (Source, sizeof(Source), NULL, "<p><table class=\"ctgry\">\n\ <tr><th class=\"ctttl\">Source: "File"</th></tr>\n\ <tr><td>\n\ <table class=\"rghtlft\">\n\ <tr><th>File:</th><td>!AZ</td><td style=\"padding-left:1em;\">\ <a class=\"abttn\" target=\"_blank\" href=\"!&;AZ\">View</a>\ </td></tr>\n\ <tr><th>Revised:</th><td>!AZ</td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n", &FaoVector); /* the administration menus, etc. are always in English (for now!) */ strcpy (tkptr->MsgStringPtr = tkptr->MsgString, "Update|Save As|Update|Create|Preview|Undo Editing|Change Edit Window"); } else { /******************************/ /* editing any other document */ /******************************/ /* retrieve the previously saved position in the string */ cptr = tkptr->MsgStringPtr; vecptr = FaoVector; /* "Document" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = Bytes; *vecptr++ = UPD_HELP_PATH; /* "Help" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* "Revised" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = DayDate; /* save the current position for use in later parts of the page */ tkptr->MsgStringPtr = cptr; if (AsNamePtr[0] && FileExists) { char ch; /* "Save As" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; ch = *cptr; *cptr = '\0'; *vecptr++ = PostPath; *vecptr++ = PostPath; status = FaolToBuffer (Source, sizeof(Source), NULL, "<table class==\"ctgry\">\n\ <tr><td>\n\ <table class=\"rghtlft\">\n\ <tr><th>!AZ:</th>\ <td><a class=\"abttn\" target=\"_blank\" \ href=\"!&%AZ\">!&;AZ</a>!AZ</td>\n\ <td style=\"padding-left:1em;\">\ <a class=\"abttn\" target=\"_blank\" href=\"!&%AZ\">!&;AZ</a></th></td>\n\ </tr>\n\ <tr><th>!&;AZ:</th><td>!&;AZ</td></tr>\n\ <tr><th>!&;AZ:</th><td>\ <a class=\"abttn\" target=\"_blank\" href=\"!&%AZ\">!&;AZ</a></td>\ </tr>\n\ </table>\n\ </td></tr>\n\ </table>\n", &FaoVector); *cptr = ch; } else { status = FaolToBuffer (Source, sizeof(Source), NULL, "<table class=\"ctgry\">\n\ <tr><td>\n\ <table class=\"rghtlft\">\n\ <tr><th>!AZ:</th>\ <td><a target=\"_blank\" href=\"!&%AZ\">!&;AZ</a>!AZ</td>\n\ <td style=\"padding-left:1em;\">\ <a class=\"abttn\" target=\"_blank\" href=\"!&%AZ\">!&;AZ</a></td>\ </tr>\n\ <tr><th>!AZ:</th><td>!AZ</td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n", &FaoVector); } } if (VMSnok (status) || status == SS$_BUFFEROVF) { rqptr->rqResponse.ErrorTextPtr = "FaolToBuffer()"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } if (!tkptr->CxR[0]) strcpy (tkptr->CxR, "80x24"); if (!FileExists && ConfigSameContentType (ContentTypePtr, "text/html", 9)) { HtmlTemplatePtr = "<HTML>\n\ <HEAD>\n\ <TITLE></TITLE>\n\ </HEAD>\n\ <BODY>\n\ </BODY>\n\ </HTML>\n"; } else HtmlTemplatePtr = ""; cptr = tkptr->CxR; tkptr->Cols = atoi(cptr); while (*cptr && TOLO(*cptr) != 'x') cptr++; if (*cptr) cptr++; tkptr->Rows = atoi(cptr); if (tkptr->Cols <= 0) tkptr->Cols = 80; else if (tkptr->Cols >= 132) tkptr->Cols = 132; if (tkptr->Rows <= 0) tkptr->Rows = 12; else if (tkptr->Rows >= 48) tkptr->Rows = 48; /* The file edit page is deliberately not pre-expired. To do so results in the page being reloaded each time it's displayed. */ ResponseHeader200 (rqptr, "text/html", NULL); /* retrieve the previously saved position in the string */ cptr = tkptr->MsgStringPtr; vecptr = FaoVector; *vecptr++ = WASD_DOCTYPE; *vecptr++ = HtmlMetaInfo (rqptr, tkptr->FileOds.ExpFileName); *vecptr++ = AdminWasdCss (); if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "<link rel=\"stylesheet\" type=\"text/css\" href=\"!AZ\">\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; /* ordinary editing or server administration file editing again */ if (ConfigEdit) { *vecptr++ = "WASD"; *vecptr++ = ServerHostPort; *vecptr++ = ADMIN_BODY_TAG; *vecptr++ = "WASD"; *vecptr++ = ServerHostPort; } else { *vecptr++ = cptr; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = ADMIN_BODY_TAG; *vecptr++ = cptr; *vecptr++ = rqptr->ServicePtr->ServerHostPort; } /* step over the "Update" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = TitlePtr; *vecptr++ = Source; *vecptr++ = PostPath; if (AsNamePtr[0]) { /* "save as" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* step over "Update" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; /* step over "Create" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; } else if (FileExists) { /* step over "save as" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; /* "Update" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* step over "Create" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; } else { /* step over "save as" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; /* step over "Update" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) cptr++; /* "Create" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; } /* "Preview" */ if (ConfigEdit) *vecptr++ = ""; else { *vecptr++ = "<input type=\"submit\" name=\"previewonly\" value=\"!AZ\">\n\ <input type=\"hidden\" name=\"previewnote\" value=\"!AZ!AZ\">\n"; *vecptr++ = cptr; if (ConfigSameContentType (ContentTypePtr, "text/html", -1)) { *vecptr++ = UPD_PREVIEW_NOTE_HTML; *vecptr++ = UPD_PREVIEW_NOTE_HTML_NEWLINE; } else if (ConfigSameContentType (ContentTypePtr, "text/x-menu", -1)) { *vecptr++ = UPD_PREVIEW_NOTE_HTML; *vecptr++ = UPD_PREVIEW_NOTE_MENU_NEWLINE; } else { *vecptr++ = UPD_PREVIEW_NOTE_PLAIN; *vecptr++ = ""; } } while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* Undo Editing */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* save the current position for use in later parts of the page */ tkptr->MsgStringPtr = cptr; /* file protection */ *vecptr++ = tkptr->ProtectionList; *vecptr++ = tkptr->Cols; *vecptr++ = tkptr->Rows; *vecptr++ = SiteLogEntry; *vecptr++ = HtmlTemplatePtr; status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } if (FileExists) AstFunction = &UpdEditFileNextRecord; else AstFunction = &UpdEditFileEnd; NetWriteFullFlush (rqptr, AstFunction); } /*****************************************************************************/ /* Queue a read of the next record from the file. When the read completes call UpdEditFileNextRecordAst() function to HTML-escape and include in the text area. */ void UpdEditFileNextRecord (REQUEST_STRUCT *rqptr) { /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdEditFileNextRecord() !&F", &UpdEditFileNextRecord); /* asynchronous get service */ rqptr->UpdTaskPtr->FileOds.Rab.rab$l_rop |= RAB$M_ASY; sys$get (&rqptr->UpdTaskPtr->FileOds.Rab, &UpdEditFileNextRecordAst, &UpdEditFileNextRecordAst); } /*****************************************************************************/ /* A record has been read. Ensure it is newline terminated. Escape any HTML-forbidden characters (it is being included within <textarea></textarea> tags!). Buffer it. */ void UpdEditFileNextRecordAst (struct RAB *RabPtr) { int rsz, status, Length; REQUEST_STRUCT *rqptr; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = RabPtr->rab$l_ctx; if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdEditFileNextRecordAst() !&F sts:!&X stv:!&X rsz:!UL\n", &UpdEditFileNextRecordAst, RabPtr->rab$l_sts, RabPtr->rab$l_stv, RabPtr->rab$w_rsz); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { UpdEnd (rqptr); return; } tkptr = rqptr->UpdTaskPtr; if (VMSnok (tkptr->FileOds.Rab.rab$l_sts)) { if (tkptr->FileOds.Rab.rab$l_sts == RMS$_EOF) { UpdEditFileEnd (rqptr); return; } rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->FileOds.ExpFileName; ErrorVmsStatus (rqptr, tkptr->FileOds.Rab.rab$l_sts, FI_LI); UpdEnd (rqptr); return; } rsz = tkptr->FileOds.Rab.rab$w_rsz; if (!tkptr->RecordFormatFixed) { /* add newline if empty, or if last character in line not a newline! */ if (rsz && tkptr->FileOds.Rab.rab$l_ubf[rsz-1] != '\n') tkptr->FileOds.Rab.rab$l_ubf[rsz++] = '\n'; else if (!rsz) tkptr->FileOds.Rab.rab$l_ubf[rsz++] = '\n'; } tkptr->FileOds.Rab.rab$l_ubf[rsz] = '\0'; status = FaoToNet (rqptr, "!&;AZ", tkptr->FileOds.Rab.rab$l_ubf); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); NetWritePartFlush (rqptr, &UpdEditFileNextRecord); } /*****************************************************************************/ /* End-of-file detected. End text area, add form submit botton, change text edit area form, etc., complete editing page HTML. */ void UpdEditFileEnd (REQUEST_STRUCT *rqptr) { int status; unsigned long FaoVector [16]; unsigned long *vecptr; char *cptr; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdEditFileEnd()"); tkptr = rqptr->UpdTaskPtr; vecptr = FaoVector; *vecptr++ = rqptr->ScriptName; *vecptr++ = rqptr->rqHeader.PathInfoPtr; /* "Change Edit Window" */ *vecptr++ = cptr = tkptr->MsgStringPtr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = tkptr->Cols; *vecptr++ = tkptr->Rows; *vecptr++ = tkptr->Cols; *vecptr++ = tkptr->Rows; status = FaolToNet (rqptr, "</textarea>\n\ </form>\n\ <p><form method=\"GET\" action=\"!&%AZ!&%AZ\">\n\ <input type=\"submit\" value=\"!AZ\">\n\ <select name=\"cxr\" id=\"cxr\" \ ONCHANGE=\"return changeEditWindow()\">\n\ <option value=\"!ULx!UL\" selected>!ULx!UL\n\ <option value=\"132x48\">132x48\n\ <option value=\"132x24\">132x24\n\ <option value=\"132x16\">132x16\n\ <option value=\"132x12\">132x12\n\ <option value=\"80x48\">80x48\n\ <option value=\"80x24\">80x24\n\ <option value=\"80x16\">80x16\n\ <option value=\"80x12\">80x12\n\ <option value=\"40x48\">40x48\n\ <option value=\"40x24\">40x24\n\ <option value=\"40x12\">40x12\n\ </select>\n\ </form>\n\ </div>\n\ </body>\n\ </html>\n", &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); } UpdEnd (rqptr); } /*****************************************************************************/ /* Rename a file. */ void UpdFileRename ( REQUEST_STRUCT *rqptr, char *OldOne, char *NewOne ) { int status, RenameCount; unsigned short Length; unsigned long Context, RenameFlags; char *cptr; char NewName [ODS_MAX_FILE_NAME_LENGTH+1], NewFileName [ODS_MAX_FILE_NAME_LENGTH+1], OldName [ODS_MAX_FILE_NAME_LENGTH+1], OldFileName [ODS_MAX_FILE_NAME_LENGTH+1], Scratch [ODS_MAX_FILE_NAME_LENGTH+1]; UPD_TASK *tkptr; $DESCRIPTOR (OldFileNameDsc, OldFileName); $DESCRIPTOR (NewFileNameDsc, NewFileName); /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdFileRename() !&Z !&Z !&Z", rqptr->rqHeader.PathInfoPtr, OldOne, NewOne); tkptr = rqptr->UpdTaskPtr; /* authentication is mandatory for a PUT, DELETE or POST */ if (!rqptr->RemoteUser[0] || !((rqptr->rqAuth.RequestCan & HTTP_METHOD_PUT) || (rqptr->rqAuth.RequestCan & HTTP_METHOD_POST) || (rqptr->rqAuth.RequestCan & HTTP_METHOD_DELETE))) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; ErrorVmsStatus (rqptr, SS$_NOPRIV, FI_LI); UpdEnd (rqptr); return; } if (!OldOne[0] || !NewOne[0] || rqptr->rqHeader.Method != HTTP_METHOD_POST) { ErrorInternal (rqptr, 0, ErrorSanityCheck, FI_LI); UpdEnd (rqptr); return; } MapOdsUrlToVms (OldOne, OldName, sizeof(OldName), '_', rqptr->rqPathSet.MapEllipsis, rqptr->PathOds); FaoToBuffer (OldFileName, sizeof(OldFileName), &Length, "!AZ!AZ", rqptr->ParseOds.ExpFileName, OldName); OldFileNameDsc.dsc$w_length = Length; MapOdsUrlToVms (NewOne, NewName, sizeof(NewName), '_', rqptr->rqPathSet.MapEllipsis, rqptr->PathOds); FaoToBuffer (NewFileName, sizeof(NewFileName), &Length, "!AZ!AZ", rqptr->ParseOds.ExpFileName, NewName); NewFileNameDsc.dsc$w_length = Length; if (WATCHPNT(rqptr) && WATCH_CATEGORY(WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE rename !AZ !AZ", OldFileName, NewFileName); if (strsame (OldName, NewName, -1)) { ErrorGeneral (rqptr, MsgFor(rqptr,MSG_UPD_RENAME_SAME), FI_LI); UpdEnd (rqptr); return; } AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_WRITE); RenameFlags = 0x1; #ifdef ODS_EXTENDED if (rqptr->PathOdsExtended) RenameFlags += 0x4; #endif /* ODS_EXTENDED */ RenameCount = Context = 0; while (VMSok (status = lib$rename_file (&OldFileNameDsc, &NewFileNameDsc, 0, 0, &RenameFlags, 0, 0, 0, 0, 0, 0, &Context))) RenameCount++; AuthAccessEnable (rqptr, 0, 0); if (!RenameCount) { rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; if (status == RMS$_FNF) { FaoToBuffer (Scratch, sizeof(Scratch), NULL, "!AZ!AZ", rqptr->rqHeader.PathInfoPtr, OldOne); rqptr->rqResponse.ErrorTextPtr = Scratch; ErrorVmsStatus (rqptr, status, FI_LI); } else if (status == RMS$_SYN) { FaoToBuffer (Scratch, sizeof(Scratch), NULL, "!AZ!AZ", rqptr->rqHeader.PathInfoPtr, NewOne); rqptr->rqResponse.ErrorTextPtr = Scratch; ErrorVmsStatus (rqptr, status, FI_LI); } else { FaoToBuffer (Scratch, sizeof(Scratch), NULL, "!AZ!AZ", rqptr->rqHeader.PathInfoPtr, NewOne); rqptr->rqResponse.ErrorTextPtr = Scratch; ErrorVmsStatus (rqptr, status, FI_LI); } UpdEnd (rqptr); return; } /***********/ /* success */ /***********/ ReportSuccess (rqptr, "!AZ !&;&_&[AZ !AZ !&;&_&[AZ\n", MsgFor(rqptr,MSG_GENERAL_FILE), rqptr->PathOds, OldName, MsgFor(rqptr,MSG_UPD_RENAMED), rqptr->PathOds, NewName); UpdEnd (rqptr); } /*****************************************************************************/ /* Copy a file by reading each 512 byte block and converting these into 4 x 128 byte, hexadecimal-encoded, form fields that can be recreated into a file when POSTed to this server (see "hexencoded" in BODY.C module). */ void UpdCopyFileBegin ( REQUEST_STRUCT *rqptr, char *AsNamePtr ) { static char ResponseFao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>!AZ !AZ</title>\n\ </head>\n\ !AZ\n\ <div class=\"wasd\">\n\ <h2>!AZ !AZ</h2>\n\ <form method=\"POST\" action=\"!&%AZ\">\n\ <input type=\"hidden\" name=\"protection\" name=\"protection\" value=\"!4XL\">\n\ <p><table class=\"ctgry\">\n\ <tr><td>\n\ <table class=\"rghtlft\">\n\ <tr><th>!AZ</th>\ <td><a class=\"alnk\" target=\"_blank\" href=\"!&%AZ\">!&;&[AZ</a></td>\ <td rowspan=\"2\" style=\"padding-left:1em;\">\ <input type=\"submit\" value=\"!AZ\">\ </td></tr>\n\ <tr><th>!AZ</th>\ <td><a class=\"alnk\" target=\"_blank\" href=\"!&%AZ\">!&;&[AZ</a>\ </td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n\ <input type=\"hidden\" name=\"fab$b_rfm\" value=\"!UL\">\n\ <input type=\"hidden\" name=\"fab$b_rat\" value=\"!UL\">\n"; int status, ByteCount, RevDayOfWeek; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr, *ToPtr; char PostPath [ODS_MAX_FILE_NAME_LENGTH+1], Scratch [256]; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdCopyFileBegin() !&Z", AsNamePtr); tkptr = rqptr->UpdTaskPtr; if (WATCHPNT(rqptr) && WATCH_CATEGORY(WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE copy !AZ", rqptr->ParseOds.ExpFileName); AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_READ); OdsOpen (&tkptr->FileOds, rqptr->ParseOds.ExpFileName, rqptr->ParseOds.ExpFileNameLength, NULL, 0, FAB$M_GET | FAB$M_BIO, 0, FAB$M_SHRGET, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status = tkptr->FileOds.Fab.fab$l_sts)) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } if (tkptr->FileOds.Fab.fab$b_org != FAB$C_SEQ) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, SS$_UNSUPPORTED, FI_LI); UpdEnd (rqptr); return; } if (VMSnok (status = OdsParseTerminate (&tkptr->FileOds))) { ErrorNoticed (rqptr, status, NULL, FI_LI); UpdEnd (rqptr); return; } /* record access block */ tkptr->FileOds.Rab = cc$rms_rab; tkptr->FileOds.Rab.rab$l_ctx = rqptr; tkptr->FileOds.Rab.rab$l_fab = &tkptr->FileOds.Fab; tkptr->FileOds.Rab.rab$l_bkt = 0; tkptr->FileOds.Rab.rab$l_rop = RAB$M_RAH | RAB$M_BIO; tkptr->FileOds.Rab.rab$l_ubf = tkptr->CopyBuffer; /* MUST be 512 bytes (one block) */ tkptr->FileOds.Rab.rab$w_usz = sizeof(tkptr->CopyBuffer); status = sys$connect (&tkptr->FileOds.Rab, 0, 0); if (VMSnok (status)) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->FileOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /**************/ /* begin page */ /**************/ /* remove any explicit version from the path to be POSTed */ zptr = (sptr = PostPath) + sizeof(PostPath); /* a full (local) path could have been supplied */ if (AsNamePtr[0] != '/') for (cptr = rqptr->rqHeader.PathInfoPtr; *cptr && sptr < zptr; *sptr++ = *cptr++); if (sptr < zptr) { /* eliminate the trailing file name */ while (sptr > PostPath && *sptr != '/') sptr--; if (*sptr == '/') sptr++; /* add the destination file name */ for (cptr = AsNamePtr; *cptr && sptr < zptr; *sptr++ = *cptr++); } if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; rqptr->rqResponse.PreExpired = PRE_EXPIRE_UPD; ResponseHeader200 (rqptr, "text/html", NULL); cptr = MsgFor(rqptr,MSG_UPD_COPY); zptr = (sptr = Scratch) + sizeof(Scratch); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; vecptr = FaoVector; *vecptr++ = WASD_DOCTYPE; *vecptr++ = HtmlMetaInfo (rqptr, NULL); *vecptr++ = AdminWasdCss (); if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "<link rel=\"stylesheet\" type=\"text/css\" href=\"!AZ\">\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; /* "Update" */ *vecptr++ = cptr = Scratch; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = ADMIN_BODY_TAG; /* "Update" again */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = PostPath; *vecptr++ = tkptr->ProtectionMask; /* "Copy" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = rqptr->PathOds; *vecptr++ = rqptr->rqHeader.PathInfoPtr; /* "Confirm" (for historical reasons "confirm" is after "to") */ ToPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* "To" */ *vecptr++ = ToPtr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = PostPath; *vecptr++ = rqptr->PathOds; *vecptr++ = PostPath; *vecptr++ = tkptr->FileOds.Fab.fab$b_rfm; *vecptr++ = tkptr->FileOds.Fab.fab$b_rat; status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } NetWriteFullFlush (rqptr, &UpdCopyFileNextBlock); } /*****************************************************************************/ /* Queue a read of the next record from the file. When the read completes call UpdCopyFileNextBlockAst() function to HTML-escape and include in the text area. */ void UpdCopyFileNextBlock (REQUEST_STRUCT *rqptr) { /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdCopyFileNextBlock() !&F", &UpdCopyFileNextBlock); rqptr->UpdTaskPtr->FileOds.Rab.rab$l_bkt++; /* asynchronous read service */ rqptr->UpdTaskPtr->FileOds.Rab.rab$l_rop |= RAB$M_ASY; sys$read (&rqptr->UpdTaskPtr->FileOds.Rab, &UpdCopyFileNextBlockAst, &UpdCopyFileNextBlockAst); } /*****************************************************************************/ /* A record has been read. Turn the record into 128 byte, hexdecimal-encoded form hidden fields. */ void UpdCopyFileNextBlockAst (struct RAB *RabPtr) { static char HexDigit [] = "0123456789ABCDEF"; static char Bucket [64]; static $DESCRIPTOR (BucketDsc, Bucket); static $DESCRIPTOR (BucketFaoDsc, "<input type=\"hidden\" name=\"hexencoded_!UL_!UL\" value=\"\0"); int cnt, status; char *cptr, *sptr; char Buffer [2048]; REQUEST_STRUCT *rqptr; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ rqptr = RabPtr->rab$l_ctx; if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdCopyFileNextBlockAst() !&F sts:!&X stv:!&X rsz:!UL\n", &UpdCopyFileNextBlockAst, RabPtr->rab$l_sts, RabPtr->rab$l_stv, RabPtr->rab$w_rsz); if (rqptr->RequestState >= REQUEST_STATE_ABORT) { UpdEnd (rqptr); return; } tkptr = rqptr->UpdTaskPtr; if (VMSnok (tkptr->FileOds.Rab.rab$l_sts)) { if (tkptr->FileOds.Rab.rab$l_sts == RMS$_EOF) { UpdCopyFileEnd (rqptr); return; } rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = tkptr->FileOds.ExpFileName; ErrorVmsStatus (rqptr, tkptr->FileOds.Rab.rab$l_sts, FI_LI); UpdEnd (rqptr); return; } sptr = Buffer; for (cnt = 0; cnt < RabPtr->rab$w_rsz; cnt++) { if (!(cnt % 128)) { if (cnt) for (cptr = "\">\n"; *cptr; *sptr++ = *cptr++); sys$fao (&BucketFaoDsc, 0, &BucketDsc, tkptr->FileOds.Rab.rab$l_bkt, cnt); for (cptr = Bucket; *cptr; *sptr++ = *cptr++); cptr = tkptr->FileOds.Rab.rab$l_ubf + cnt; } *sptr++ = HexDigit[((unsigned char)*cptr & 0xf0) >> 4]; *sptr++ = HexDigit[(unsigned char)*cptr & 0x0f]; cptr++; } for (cptr = "\">\n"; *cptr; *sptr++ = *cptr++); *sptr = '\0'; NetWriteBuffered (rqptr, &UpdCopyFileNextBlock, Buffer, sptr-Buffer); } /*****************************************************************************/ /* End-of-file detected. */ void UpdCopyFileEnd (REQUEST_STRUCT *rqptr) { static char CopyFileEndFao [] = "</form>\n\ </div>\n\ </body>\n\ </html>\n"; int status; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdCopyFileEnd()"); status = FaolToNet (rqptr, CopyFileEndFao, NULL); if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI); UpdEnd (rqptr); } /*****************************************************************************/ /* Output HTML allowing confirmation of directory creation. */ void UpdConfirmMkdir ( REQUEST_STRUCT *rqptr, char *AsNamePtr ) { static char ResponseFao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>!AZ !AZ</title>\n\ </head>\n\ !AZ\n\ <div class=\"wasd\">\n\ <h2>!AZ !AZ</h2>\n\ <form method=\"POST\" action=\"!&%AZ!&%AZ/\">\n\ <input type=\"hidden\" name=\"protection\" value=\"!4XL\">\n\ <table class=\"ctgry\">\n\ <tr><td>\n\ <table class=\"rghtlft\">\n\ <th>!AZ</th><td>\ <a class=\"alnk\" target=\"_blank\" href=\"!&%AZ!&%AZ/\">!&;AZ!&;AZ/</a>\ </td><td style=\"padding-left:1em;\">\ <input type=\"submit\" value=\"!AZ\"></td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n\ </form>\n\ </div>\n\ </body>\n\ </html>\n"; int status; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr; char Scratch [256]; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdConfirmMkdir() !&Z", AsNamePtr); tkptr = rqptr->UpdTaskPtr; rqptr->rqResponse.PreExpired = PRE_EXPIRE_UPD; ResponseHeader200 (rqptr, "text/html", NULL); cptr = MsgFor(rqptr,MSG_UPD_CREATE); zptr = (sptr = Scratch) + sizeof(Scratch); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; vecptr = FaoVector; *vecptr++ = WASD_DOCTYPE; *vecptr++ = HtmlMetaInfo (rqptr, NULL); *vecptr++ = AdminWasdCss (); if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "<link rel=\"stylesheet\" type=\"text/css\" href=\"!AZ\">\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; /* "Update" */ *vecptr++ = cptr = Scratch; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = ADMIN_BODY_TAG; /* "Update" again */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = AsNamePtr; *vecptr++ = tkptr->ProtectionMask; /* "Create" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = AsNamePtr; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = AsNamePtr; /* "Confirm" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); } UpdEnd (rqptr); } /*****************************************************************************/ /* Output HTML allowing confirmation of directory deletion. */ void UpdConfirmDelete ( REQUEST_STRUCT *rqptr, char *Name, char *Slash ) { static char ResponseFao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>!AZ !AZ</title>\n\ </head>\n\ !AZ\n\ <div class=\"wasd\">\n\ <h2>!AZ !AZ</h2>\n\ <form method=\"POST\" action=\"!&%AZ!&%AZ!&%AZ;*\">\n\ <table class=\"ctgry\">\n\ <tr><td>\n\ <table class=\"rghtlft\">\n\ <tr><th>!AZ</th><td>\ <a class=\"alnk\" target=\"_blank\" href=\"!&%AZ!&%AZ!AZ\">!&;AZ!&;AZ!AZ</a>\ </td><td style=\"padding-left:1em;\">\ <input type=\"submit\" value=\"!AZ\"></td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n\ </form>\n\ </div>\n\ </body>\n\ </html>\n"; int status; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr; char Scratch [256]; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdConfirmDelete() !&Z !&Z", Name, Slash); tkptr = rqptr->UpdTaskPtr; rqptr->rqResponse.PreExpired = PRE_EXPIRE_UPD; ResponseHeader200 (rqptr, "text/html", NULL); cptr = MsgFor(rqptr,MSG_UPD_DELETE); zptr = (sptr = Scratch) + sizeof(Scratch); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; vecptr = FaoVector; *vecptr++ = WASD_DOCTYPE; *vecptr++ = HtmlMetaInfo (rqptr, NULL); *vecptr++ = AdminWasdCss (); if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "<link rel=\"stylesheet\" type=\"text/css\" href=\"!AZ\">\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; /* "Update" */ *vecptr++ = cptr = Scratch; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = ADMIN_BODY_TAG; /* "Update" again */ *vecptr++ = cptr; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = Name; *vecptr++ = Slash; /* "delete" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = cptr; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = Name; *vecptr++ = Slash; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = Name; *vecptr++ = Slash; /* "Confirm" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = cptr; status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); } UpdEnd (rqptr); } /*****************************************************************************/ /* Output HTML allowing confirmation of protection change. */ void UpdConfirmProtect ( REQUEST_STRUCT *rqptr, char *Name, char *Slash ) { static char ResponseFao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>!AZ !AZ</title>\n\ </head>\n\ !AZ\n\ <div class=\"wasd\">\n\ <h2>!AZ !AZ</h2>\n\ <form method=\"POST\" action=\"!&%AZ!&%AZ!&%AZ!&%AZ\">\n\ <table class=\"ctgry\">\n\ <tr><td>\n\ <table class=\"rghtlft\">\n\ <tr><th>!AZ</th><td>\ <a class=\"alnk\" target=\"_blank\" href=\"!&%AZ!&%AZ!AZ\">!&;AZ!&;AZ!AZ</a>\ </td><td>!AZ</td><td>!AZ</td><td style=\"padding-left:1em;\">\n\ <input type=\"hidden\" name=\"d-dirprotect\" value=\"1\">\n\ <input type=\"hidden\" name=\"protection\" value=\"!4XL\">\n\ <input type=\"submit\" value=\"!AZ\">\n\ </td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n\ </form>\n\ </div>\n\ </body>\n\ </html>\n"; int status; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr; char ProtectionString[32], Scratch [256]; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdConfirmProtect() !&Z !&Z", Name, Slash); tkptr = rqptr->UpdTaskPtr; FormatProtection (tkptr->ProtectionMask, ProtectionString); rqptr->rqResponse.PreExpired = PRE_EXPIRE_UPD; ResponseHeader200 (rqptr, "text/html", NULL); cptr = MsgFor(rqptr,MSG_UPD_PROTECTION); zptr = (sptr = Scratch) + sizeof(Scratch); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; vecptr = FaoVector; *vecptr++ = WASD_DOCTYPE; *vecptr++ = HtmlMetaInfo (rqptr, NULL); *vecptr++ = AdminWasdCss (); if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "<link rel=\"stylesheet\" type=\"text/css\" href=\"!AZ\">\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; /* "Update" */ *vecptr++ = cptr = Scratch; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = ADMIN_BODY_TAG; /* "Update" again */ *vecptr++ = cptr; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = rqptr->ScriptName; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = Name; *vecptr++ = Slash; /* "protect" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = cptr; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = Name; *vecptr++ = Slash; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = Name; *vecptr++ = Slash; /* "to" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = cptr; *vecptr++ = ProtectionString; *vecptr++ = tkptr->ProtectionMask; /* "Confirm" */ while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = cptr; status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); } UpdEnd (rqptr); } /*****************************************************************************/ /* Output HTML allowing confirmation of action (file/directory creation/deletion). */ void UpdConfirmRename ( REQUEST_STRUCT *rqptr, char *OldName, char *NewName ) { static char ResponseFao [] = "!AZ\ <html>\n\ <head>\n\ !AZ\ !AZ\ !&@\ <title>!AZ !AZ</title>\n\ </head>\n\ !AZ\n\ <div class=\"wasd\">\n\ <h2>!AZ !AZ</h2>\n\ <form method=\"POST\" action=\"!&%AZ!&%AZ\">\n\ <input type=\"hidden\" name=\"d-filerename\" value=\"1\">\n\ <input type=\"hidden\" name=\"name\" value=\"!AZ\">\n\ <input type=\"hidden\" name=\"as\" value=\"!AZ\">\n\ <p><table class=\"ctgry\">\n\ <tr><td>\n\ <table class=\"rghtlft\">\n\ <tr><th>!AZ</th>\ <td><a class=\"alnk\" target=\"_blank\" href=\"!&%AZ!&%AZ\">!&;AZ!&;AZ</a></td>\ <td rowspan=\"2\">\ <input type=\"submit\" value=\"!AZ\">\ </td></tr>\n\ <tr><th>!AZ</th>\ <td><a class=\"alnk\" target=\"_blank\" href=\"!&%AZ!&%AZ\">!&;AZ!&;AZ</a></td></tr>\n\ </table>\n\ </td></tr>\n\ </table>\n\ </form>\n\ </div>\n\ </body>\n\ </html>\n"; int status; unsigned long FaoVector [32]; unsigned long *vecptr; char *cptr, *sptr, *zptr, *ToPtr; char Scratch [256]; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdConfirmRename() !&Z !&Z", OldName, NewName); tkptr = rqptr->UpdTaskPtr; rqptr->rqResponse.PreExpired = PRE_EXPIRE_UPD; ResponseHeader200 (rqptr, "text/html", NULL); cptr = MsgFor(rqptr,MSG_UPD_RENAME); zptr = (sptr = Scratch) + sizeof(Scratch); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { ErrorGeneralOverflow (rqptr, FI_LI); UpdEnd (rqptr); return; } *sptr = '\0'; vecptr = FaoVector; *vecptr++ = WASD_DOCTYPE; *vecptr++ = HtmlMetaInfo (rqptr, NULL); *vecptr++ = AdminWasdCss (); if (rqptr->rqPathSet.StyleSheetPtr) { *vecptr++ = "<link rel=\"stylesheet\" type=\"text/css\" href=\"!AZ\">\n"; *vecptr++ = rqptr->rqPathSet.StyleSheetPtr; } else *vecptr++ = ""; /* "Update" */ *vecptr++ = cptr = Scratch; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = ADMIN_BODY_TAG; /* "Update" again */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = rqptr->ServicePtr->ServerHostPort; *vecptr++ = rqptr->ScriptName; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = OldName, *vecptr++ = NewName, /* "Rename" */ *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = OldName, *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = OldName, /* "Confirm" (for historical reasons "confirm" is after "to") */ ToPtr = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; *vecptr++ = cptr; while (*cptr && *cptr != '|') cptr++; if (*cptr) *cptr++ = '\0'; /* "to" */ *vecptr++ = ToPtr; *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = NewName, *vecptr++ = rqptr->rqHeader.PathInfoPtr; *vecptr++ = NewName, status = FaolToNet (rqptr, ResponseFao, &FaoVector); if (VMSnok (status)) { ErrorNoticed (rqptr, status, NULL, FI_LI); rqptr->rqResponse.ErrorTextPtr = "FaolToNet()"; ErrorVmsStatus (rqptr, status, FI_LI); } UpdEnd (rqptr); } /*****************************************************************************/ /* Update the protection of rqptr->ParseOds.ExpFileName. */ void UpdProtection (REQUEST_STRUCT *rqptr) { static unsigned short EnsureSystemAccessMask = 0xfff0; /* S:RWED */ int status, Length; unsigned short ProtectionMask; char *cptr; char DirFile [ODS_MAX_FILE_NAME_LENGTH+1], ProtectionString[32]; UPD_TASK *tkptr; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_UPD)) WatchThis (WATCHITM(rqptr), WATCH_MOD_UPD, "UpdProtection()"); tkptr = rqptr->UpdTaskPtr; if (WATCHPNT(rqptr) && WATCH_CATEGORY(WATCH_RESPONSE)) WatchThis (WATCHITM(rqptr), WATCH_RESPONSE, "UPDATE protection !AZ", rqptr->ParseOds.ExpFileName); /* authentication is mandatory for such an update */ if (!rqptr->RemoteUser[0] || !((rqptr->rqAuth.RequestCan & HTTP_METHOD_PUT) || (rqptr->rqAuth.RequestCan & HTTP_METHOD_POST) || (rqptr->rqAuth.RequestCan & HTTP_METHOD_DELETE))) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, SS$_NOPRIV, FI_LI); UpdEnd (rqptr); return; } cptr = rqptr->ParseOds.ExpFileName; Length = rqptr->ParseOds.ExpFileNameLength; if (!rqptr->ParseOds.NamNameLength && !rqptr->ParseOds.NamTypeLength) OdsNameOfDirectoryFile (rqptr->ParseOds.ExpFileName, Length, cptr = DirFile, &Length); ProtectionMask = tkptr->ProtectionMask & EnsureSystemAccessMask; status = OdsParse (&tkptr->FileOds, cptr, Length, NULL, 0, 0, NULL, rqptr); AuthAccessEnable (rqptr, rqptr->ParseOds.ExpFileName, AUTH_ACCESS_WRITE); status = OdsFileAcpModify (&tkptr->FileOds, &ProtectionMask, NULL, NULL, rqptr); AuthAccessEnable (rqptr, 0, 0); if (VMSnok (status)) { rqptr->rqResponse.ErrorTextPtr = rqptr->rqHeader.PathInfoPtr; rqptr->rqResponse.ErrorOtherTextPtr = rqptr->ParseOds.ExpFileName; ErrorVmsStatus (rqptr, status, FI_LI); UpdEnd (rqptr); return; } /***********/ /* success */ /***********/ FormatProtection (tkptr->ProtectionMask, ProtectionString); ReportSuccess (rqptr, "!AZ <a target=\"_blank\" href=\"!&%AZ\">!&;&_AZ</a>\ !AZ (!AZ)\n", MsgFor(rqptr,MSG_GENERAL_FILE), rqptr->rqHeader.PathInfoPtr, rqptr->rqHeader.PathInfoPtr, MsgFor(rqptr,MSG_UPD_PROTECTION_CHANGED), ProtectionString); UpdEnd (rqptr); } /*****************************************************************************/