526 if ($2 && $4 != NULL) { 527 argv[2] = $4; 528 retrieve(argv, $4); 529 } 530 if ($4 != NULL) 531 free($4); 532 } 533 534 | NLST check_login CRLF 535 { 536 if ($2) 537 send_file_list("."); 538 } 539 540 | NLST check_login SP pathname CRLF 541 { 542 if ($2) 543 send_file_list($4); 544 free($4); 545 } 546 547 | SITE SP HELP CRLF 548 { 549 help(sitetab, NULL); 550 } 551 552 | SITE SP CHMOD SP octal_number SP pathname CRLF 553 { 554 if (check_write($7, 0)) { 555 if (($5 == -1) || ($5 > 0777)) 556 reply(501, 557 "CHMOD: Mode value must be between 0 and 0777"); 558 else if (chmod($7, $5) < 0) 559 perror_reply(550, $7); 560 else 561 reply(200, "CHMOD command successful."); 562 } 563 if ($7 != NULL) 564 free($7); 565 } 566 567 | SITE SP HELP SP STRING CRLF 568 { 569 help(sitetab, $5); 570 free($5); 571 } 572 573 | SITE SP IDLE check_login CRLF 574 { 575 if ($4) { 576 reply(200, 577 "Current IDLE time limit is " LLF 578 " seconds; max " LLF, 579 (LLT)curclass.timeout, 580 (LLT)curclass.maxtimeout); 581 } 582 } 583 584 | SITE SP IDLE check_login SP NUMBER CRLF 585 { 586 if ($4) { 587 if ($6.i < 30 || $6.i > curclass.maxtimeout) { 588 reply(501, 589 "IDLE time limit must be between 30 and " 590 LLF " seconds", 591 (LLT)curclass.maxtimeout); 592 } else { 593 curclass.timeout = $6.i; 594 (void) alarm(curclass.timeout); 595 reply(200, 596 "IDLE time limit set to " 597 LLF " seconds", 598 (LLT)curclass.timeout); 599 } 600 } 601 } 602 603 | SITE SP RATEGET check_login CRLF 604 { 605 if ($4) { 606 reply(200, 607 "Current RATEGET is " LLF " bytes/sec", 608 (LLT)curclass.rateget); 609 } 610 } 611 612 | SITE SP RATEGET check_login SP STRING CRLF 613 { 614 char errbuf[100]; 615 char *p = $6; 616 LLT rate; 617 618 if ($4) { 619 rate = strsuftollx("RATEGET", p, 0, 620 curclass.maxrateget 621 ? curclass.maxrateget 622 : LLTMAX, errbuf, sizeof(errbuf)); 623 if (errbuf[0]) 624 reply(501, "%s", errbuf); 625 else { 626 curclass.rateget = rate; 627 reply(200, 628 "RATEGET set to " LLF " bytes/sec", 629 (LLT)curclass.rateget); 630 } 631 } 632 free($6); 633 } 634 635 | SITE SP RATEPUT check_login CRLF 636 { 637 if ($4) { 638 reply(200, 639 "Current RATEPUT is " LLF " bytes/sec", 640 (LLT)curclass.rateput); 641 } 642 } 643 644 | SITE SP RATEPUT check_login SP STRING CRLF 645 { 646 char errbuf[100]; 647 char *p = $6; 648 LLT rate; 649 650 if ($4) { 651 rate = strsuftollx("RATEPUT", p, 0, 652 curclass.maxrateput 653 ? curclass.maxrateput 654 : LLTMAX, errbuf, sizeof(errbuf)); 655 if (errbuf[0]) 656 reply(501, "%s", errbuf); 657 else { 658 curclass.rateput = rate; 659 reply(200, 660 "RATEPUT set to " LLF " bytes/sec", 661 (LLT)curclass.rateput); 662 } 663 } 664 free($6); 665 } 666 667 | SITE SP UMASK check_login CRLF 668 { 669 int oldmask; 670 671 if ($4) { 672 oldmask = umask(0); 673 (void) umask(oldmask); 674 reply(200, "Current UMASK is %03o", oldmask); 675 } 676 } 677 678 | SITE SP UMASK check_login SP octal_number CRLF 679 { 680 int oldmask; 681 682 if ($4 && check_write("", 0)) { 683 if (($6 == -1) || ($6 > 0777)) { 684 reply(501, "Bad UMASK value"); 685 } else { 686 oldmask = umask($6); 687 reply(200, 688 "UMASK set to %03o (was %03o)", 689 $6, oldmask); 690 } 691 } 692 } 693 694 | SYST CRLF 695 { 696 if (EMPTYSTR(version)) 697 reply(215, "UNIX Type: L%d", NBBY); 698 else 699 reply(215, "UNIX Type: L%d Version: %s", NBBY, 700 version); 701 } 702 703 | STAT check_login SP pathname CRLF 704 { 705 if ($2 && $4 != NULL) 706 statfilecmd($4); 707 if ($4 != NULL) 708 free($4); 709 } 710 711 | STAT CRLF 712 { 713 if (is_oob) 714 statxfer(); 715 else 716 statcmd(); 717 } 718 719 | HELP CRLF 720 { 721 help(cmdtab, NULL); 722 } 723 724 | HELP SP STRING CRLF 725 { 726 char *cp = $3; 727 728 if (strncasecmp(cp, "SITE", 4) == 0) { 729 cp = $3 + 4; 730 if (*cp == ' ') 731 cp++; 732 if (*cp) 733 help(sitetab, cp); 734 else 735 help(sitetab, NULL); 736 } else 737 help(cmdtab, $3); 738 free($3); 739 } 740 741 | NOOP CRLF 742 { 743 reply(200, "NOOP command successful."); 744 } 745 746 /* RFC 2228 */ 747 | AUTH SP mechanism_name CRLF 748 { 749 reply(502, "RFC 2228 authentication not implemented."); 750 free($3); 751 } 752 753 | ADAT SP base64data CRLF 754 { 755 reply(503, 756 "Please set authentication state with AUTH."); 757 free($3); 758 } 759 760 | PROT SP prot_code CRLF 761 { 762 reply(503, 763 "Please set protection buffer size with PBSZ."); 764 free($3); 765 } 766 767 | PBSZ SP decimal_integer CRLF 768 { 769 reply(503, 770 "Please set authentication state with AUTH."); 771 } 772 773 | CCC CRLF 774 { 775 reply(533, "No protection enabled."); 776 } 777 778 | MIC SP base64data CRLF 779 { 780 reply(502, "RFC 2228 authentication not implemented."); 781 free($3); 782 } 783 784 | CONF SP base64data CRLF 785 { 786 reply(502, "RFC 2228 authentication not implemented."); 787 free($3); 788 } 789 790 | ENC SP base64data CRLF 791 { 792 reply(502, "RFC 2228 authentication not implemented."); 793 free($3); 794 } 795 796 /* RFC 2389 */ 797 | FEAT CRLF 798 { 799 800 feat(); 801 } 802 803 | OPTS SP STRING CRLF 804 { 805 806 opts($3); 807 free($3); 808 } 809 810 811 /* extensions from draft-ietf-ftpext-mlst-11 */ 812 813 /* 814 * Return size of file in a format suitable for 815 * using with RESTART (we just count bytes). 816 */ 817 | SIZE check_login SP pathname CRLF 818 { 819 if ($2 && $4 != NULL) 820 sizecmd($4); 821 if ($4 != NULL) 822 free($4); 823 } 824 825 /* 826 * Return modification time of file as an ISO 3307 827 * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx 828 * where xxx is the fractional second (of any precision, 829 * not necessarily 3 digits) 830 */ 831 | MDTM check_login SP pathname CRLF 832 { 833 if ($2 && $4 != NULL) { 834 struct stat stbuf; 835 if (stat($4, &stbuf) < 0) 836 perror_reply(550, $4); 837 else if (!S_ISREG(stbuf.st_mode)) { 838 reply(550, "%s: not a plain file.", $4); 839 } else { 840 struct tm *t; 841 842 t = gmtime(&stbuf.st_mtime); 843 reply(213, 844 "%04d%02d%02d%02d%02d%02d", 845 TM_YEAR_BASE + t->tm_year, 846 t->tm_mon+1, t->tm_mday, 847 t->tm_hour, t->tm_min, t->tm_sec); 848 } 849 } 850 if ($4 != NULL) 851 free($4); 852 } 853 854 | MLST check_login SP pathname CRLF 855 { 856 if ($2 && $4 != NULL) 857 mlst($4); 858 if ($4 != NULL) 859 free($4); 860 } 861 862 | MLST check_login CRLF 863 { 864 mlst(NULL); 865 } 866 867 | MLSD check_login SP pathname CRLF 868 { 869 if ($2 && $4 != NULL) 870 mlsd($4); 871 if ($4 != NULL) 872 free($4); 873 } 874 875 | MLSD check_login CRLF 876 { 877 mlsd(NULL); 878 } 879 880 | error CRLF 881 { 882 yyerrok; 883 } 884 ; 885 886rcmd 887 : REST check_login SP NUMBER CRLF 888 { 889 if ($2) { 890 REASSIGN(fromname, NULL); 891 restart_point = (off_t)$4.ll; 892 reply(350, 893 "Restarting at " LLF ". Send STORE or RETRIEVE to initiate transfer.", 894 (LLT)restart_point); 895 } 896 } 897 898 | RNFR SP pathname CRLF 899 { 900 restart_point = (off_t) 0; 901 if (check_write($3, 0)) { 902 REASSIGN(fromname, NULL); 903 fromname = renamefrom($3); 904 } 905 if ($3 != NULL) 906 free($3); 907 } 908 ; 909 910username 911 : STRING 912 ; 913 914password 915 : /* empty */ 916 { 917 $$ = (char *)calloc(1, sizeof(char)); 918 } 919 920 | STRING 921 ; 922 923byte_size 924 : NUMBER 925 { 926 $$ = $1.i; 927 } 928 ; 929 930host_port 931 : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 932 NUMBER COMMA NUMBER 933 { 934 char *a, *p; 935 936 memset(&data_dest, 0, sizeof(data_dest)); 937 data_dest.su_len = sizeof(struct sockaddr_in); 938 data_dest.su_family = AF_INET; 939 p = (char *)&data_dest.su_port; 940 p[0] = $9.i; p[1] = $11.i; 941 a = (char *)&data_dest.su_addr; 942 a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i; 943 } 944 ; 945 946host_long_port4 947 : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 948 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 949 NUMBER 950 { 951 char *a, *p; 952 953 memset(&data_dest, 0, sizeof(data_dest)); 954 data_dest.su_len = sizeof(struct sockaddr_in); 955 data_dest.su_family = AF_INET; 956 p = (char *)&data_dest.su_port; 957 p[0] = $15.i; p[1] = $17.i; 958 a = (char *)&data_dest.su_addr; 959 a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 960 961 /* reject invalid LPRT command */ 962 if ($1.i != 4 || $3.i != 4 || $13.i != 2) 963 memset(&data_dest, 0, sizeof(data_dest)); 964 } 965 ; 966 967host_long_port6 968 : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 969 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 970 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 971 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 972 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 973 NUMBER 974 { 975#ifdef INET6 976 char *a, *p; 977 978 memset(&data_dest, 0, sizeof(data_dest)); 979 data_dest.su_len = sizeof(struct sockaddr_in6); 980 data_dest.su_family = AF_INET6; 981 p = (char *)&data_dest.su_port; 982 p[0] = $39.i; p[1] = $41.i; 983 a = (char *)&data_dest.si_su.su_sin6.sin6_addr; 984 a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 985 a[4] = $13.i; a[5] = $15.i; a[6] = $17.i; a[7] = $19.i; 986 a[8] = $21.i; a[9] = $23.i; a[10] = $25.i; a[11] = $27.i; 987 a[12] = $29.i; a[13] = $31.i; a[14] = $33.i; a[15] = $35.i; 988 if (his_addr.su_family == AF_INET6) { 989 /* XXX: more sanity checks! */ 990 data_dest.su_scope_id = his_addr.su_scope_id; 991 } 992#else 993 memset(&data_dest, 0, sizeof(data_dest)); 994#endif /* INET6 */ 995 /* reject invalid LPRT command */ 996 if ($1.i != 6 || $3.i != 16 || $37.i != 2) 997 memset(&data_dest, 0, sizeof(data_dest)); 998 } 999 ; 1000 1001form_code 1002 : N 1003 { 1004 $$ = FORM_N; 1005 } 1006 1007 | T 1008 { 1009 $$ = FORM_T; 1010 } 1011 1012 | C 1013 { 1014 $$ = FORM_C; 1015 } 1016 ; 1017 1018type_code 1019 : A 1020 { 1021 cmd_type = TYPE_A; 1022 cmd_form = FORM_N; 1023 } 1024 1025 | A SP form_code 1026 { 1027 cmd_type = TYPE_A; 1028 cmd_form = $3; 1029 } 1030 1031 | E 1032 { 1033 cmd_type = TYPE_E; 1034 cmd_form = FORM_N; 1035 } 1036 1037 | E SP form_code 1038 { 1039 cmd_type = TYPE_E; 1040 cmd_form = $3; 1041 } 1042 1043 | I 1044 { 1045 cmd_type = TYPE_I; 1046 } 1047 1048 | L 1049 { 1050 cmd_type = TYPE_L; 1051 cmd_bytesz = NBBY; 1052 } 1053 1054 | L SP byte_size 1055 { 1056 cmd_type = TYPE_L; 1057 cmd_bytesz = $3; 1058 } 1059 1060 /* this is for a bug in the BBN ftp */ 1061 | L byte_size 1062 { 1063 cmd_type = TYPE_L; 1064 cmd_bytesz = $2; 1065 } 1066 ; 1067 1068struct_code 1069 : F 1070 { 1071 $$ = STRU_F; 1072 } 1073 1074 | R 1075 { 1076 $$ = STRU_R; 1077 } 1078 1079 | P 1080 { 1081 $$ = STRU_P; 1082 } 1083 ; 1084 1085mode_code 1086 : S 1087 { 1088 $$ = MODE_S; 1089 } 1090 1091 | B 1092 { 1093 $$ = MODE_B; 1094 } 1095 1096 | C 1097 { 1098 $$ = MODE_C; 1099 } 1100 ; 1101 1102pathname 1103 : pathstring 1104 { 1105 /* 1106 * Problem: this production is used for all pathname 1107 * processing, but only gives a 550 error reply. 1108 * This is a valid reply in some cases but not in 1109 * others. 1110 */ 1111 if (logged_in && $1 && *$1 == '~') { 1112 char *path, *home, *result; 1113 size_t len; 1114 1115 path = strchr($1 + 1, '/'); 1116 if (path != NULL) 1117 *path++ = '\0'; 1118 if ($1[1] == '\0') 1119 home = homedir; 1120 else { 1121 struct passwd *hpw; 1122 1123 if ((hpw = getpwnam($1 + 1)) != NULL) 1124 home = hpw->pw_dir; 1125 else 1126 home = $1; 1127 } 1128 len = strlen(home) + 1; 1129 if (path != NULL) 1130 len += strlen(path) + 1; 1131 if ((result = malloc(len)) == NULL) 1132 fatal("Local resource failure: malloc"); 1133 strlcpy(result, home, len); 1134 if (path != NULL) { 1135 strlcat(result, "/", len); 1136 strlcat(result, path, len); 1137 } 1138 $$ = result; 1139 free($1); 1140 } else 1141 $$ = $1; 1142 } 1143 ; 1144 1145pathstring 1146 : STRING 1147 ; 1148 1149octal_number 1150 : NUMBER 1151 { 1152 int ret, dec, multby, digit; 1153 1154 /* 1155 * Convert a number that was read as decimal number 1156 * to what it would be if it had been read as octal. 1157 */ 1158 dec = $1.i; 1159 multby = 1; 1160 ret = 0; 1161 while (dec) { 1162 digit = dec%10; 1163 if (digit > 7) { 1164 ret = -1; 1165 break; 1166 } 1167 ret += digit * multby; 1168 multby *= 8; 1169 dec /= 10; 1170 } 1171 $$ = ret; 1172 } 1173 ; 1174 1175mechanism_name 1176 : STRING 1177 ; 1178 1179base64data 1180 : STRING 1181 ; 1182 1183prot_code 1184 : STRING 1185 ; 1186 1187decimal_integer 1188 : NUMBER 1189 { 1190 $$ = $1.i; 1191 } 1192 ; 1193 1194check_login 1195 : /* empty */ 1196 { 1197 if (logged_in) 1198 $$ = 1; 1199 else { 1200 reply(530, "Please login with USER and PASS."); 1201 $$ = 0; 1202 hasyyerrored = 1; 1203 } 1204 } 1205 ; 1206 1207%% 1208 1209#define CMD 0 /* beginning of command */ 1210#define ARGS 1 /* expect miscellaneous arguments */ 1211#define STR1 2 /* expect SP followed by STRING */ 1212#define STR2 3 /* expect STRING */ 1213#define OSTR 4 /* optional SP then STRING */ 1214#define ZSTR1 5 /* SP then optional STRING */ 1215#define ZSTR2 6 /* optional STRING after SP */ 1216#define SITECMD 7 /* SITE command */ 1217#define NSTR 8 /* Number followed by a string */ 1218#define NOARGS 9 /* No arguments allowed */ 1219#define EOLN 10 /* End of line */ 1220 1221struct tab cmdtab[] = { 1222 /* From RFC 959, in order defined (5.3.1) */ 1223 { "USER", USER, STR1, 1, "<sp> username" }, 1224 { "PASS", PASS, ZSTR1, 1, "<sp> password" }, 1225 { "ACCT", ACCT, STR1, 0, "(specify account)" }, 1226 { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1227 { "CDUP", CDUP, NOARGS, 1, "(change to parent directory)" }, 1228 { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 1229 { "QUIT", QUIT, NOARGS, 1, "(terminate service)" }, 1230 { "REIN", REIN, NOARGS, 0, "(reinitialize server state)" }, 1231 { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4, b5" }, 1232 { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 1233 { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 1234 { "PASV", PASV, NOARGS, 1, "(set server in passive mode)" }, 1235 { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 1236 { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1237 { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, 1238 { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 1239 { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 1240 { "RETR", RETR, STR1, 1, "<sp> file-name" }, 1241 { "STOR", STOR, STR1, 1, "<sp> file-name" }, 1242 { "STOU", STOU, STR1, 1, "<sp> file-name" }, 1243 { "APPE", APPE, STR1, 1, "<sp> file-name" }, 1244 { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 1245 { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 1246 { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 1247 { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 1248 { "ABOR", ABOR, NOARGS, 4, "(abort operation)" }, 1249 { "DELE", DELE, STR1, 1, "<sp> file-name" }, 1250 { "RMD", RMD, STR1, 1, "<sp> path-name" }, 1251 { "MKD", MKD, STR1, 1, "<sp> path-name" }, 1252 { "PWD", PWD, NOARGS, 1, "(return current directory)" }, 1253 { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 1254 { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 1255 { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 1256 { "SYST", SYST, NOARGS, 1, "(get type of operating system)" }, 1257 { "STAT", STAT, OSTR, 4, "[ <sp> path-name ]" }, 1258 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1259 { "NOOP", NOOP, NOARGS, 2, "" }, 1260 1261 /* From RFC 2228, in order defined */ 1262 { "AUTH", AUTH, STR1, 1, "<sp> mechanism-name" }, 1263 { "ADAT", ADAT, STR1, 1, "<sp> base-64-data" }, 1264 { "PROT", PROT, STR1, 1, "<sp> prot-code" }, 1265 { "PBSZ", PBSZ, ARGS, 1, "<sp> decimal-integer" }, 1266 { "CCC", CCC, NOARGS, 1, "(Disable data protection)" }, 1267 { "MIC", MIC, STR1, 4, "<sp> base64data" }, 1268 { "CONF", CONF, STR1, 4, "<sp> base64data" }, 1269 { "ENC", ENC, STR1, 4, "<sp> base64data" }, 1270 1271 /* From RFC 2389, in order defined */ 1272 { "FEAT", FEAT, NOARGS, 1, "(display extended features)" }, 1273 { "OPTS", OPTS, STR1, 1, "<sp> command [ <sp> options ]" }, 1274 1275 /* from draft-ietf-ftpext-mlst-11 */ 1276 { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 1277 { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 1278 { "MLST", MLST, OSTR, 2, "[ <sp> path-name ]" }, 1279 { "MLSD", MLSD, OSTR, 1, "[ <sp> directory-name ]" }, 1280 1281 /* obsolete commands */ 1282 { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 1283 { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 1284 { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 1285 { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 1286 { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 1287 { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 1288 { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 1289 { "XCUP", CDUP, NOARGS, 1, "(change to parent directory)" }, 1290 { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1291 { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 1292 { "XPWD", PWD, NOARGS, 1, "(return current directory)" }, 1293 { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 1294 1295 { NULL, 0, 0, 0, 0 } 1296}; 1297 1298struct tab sitetab[] = { 1299 { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 1300 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1301 { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 1302 { "RATEGET", RATEGET,OSTR, 1, "[ <sp> get-throttle-rate ]" }, 1303 { "RATEPUT", RATEPUT,OSTR, 1, "[ <sp> put-throttle-rate ]" }, 1304 { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 1305 { NULL, 0, 0, 0, NULL } 1306}; 1307
|