Fossil SCM
Lots of additional error checking on the "fossil smtpd" input.
Commit
cf1c84299ff071c85a5e40357c96c88e569a8231f34762717d65cce43b8d3880
Parent
e4144ced8dc73a3…
1 file changed
+80
-10
+80
-10
| --- src/smtp.c | ||
| +++ src/smtp.c | ||
| @@ -688,10 +688,11 @@ | ||
| 688 | 688 | |
| 689 | 689 | #define SMTPSRV_CLEAR_MSG 1 /* smtp_server_clear() last message only */ |
| 690 | 690 | #define SMTPSRV_CLEAR_ALL 2 /* smtp_server_clear() everything */ |
| 691 | 691 | #define SMTPSRV_LOG 0x001 /* Record a transcript of the interaction */ |
| 692 | 692 | #define SMTPSRV_STDERR 0x002 /* Transcription written to stderr */ |
| 693 | +#define SMTPSRV_DRYRUN 0x004 /* Do not record anything in database */ | |
| 693 | 694 | |
| 694 | 695 | #endif /* LOCAL_INTERFACE */ |
| 695 | 696 | |
| 696 | 697 | /* |
| 697 | 698 | ** Clear the SmtpServer object. Deallocate resources. |
| @@ -873,11 +874,15 @@ | ||
| 873 | 874 | ** Add this email to the database. |
| 874 | 875 | */ |
| 875 | 876 | static void smtp_server_route_incoming(SmtpServer *p, int bFinish){ |
| 876 | 877 | Stmt s; |
| 877 | 878 | int i, j; |
| 878 | - if( p->zFrom && p->nTo && blob_size(&p->msg) ){ | |
| 879 | + if( p->zFrom | |
| 880 | + && p->nTo | |
| 881 | + && blob_size(&p->msg) | |
| 882 | + && (p->srvrFlags & SMTPSRV_DRYRUN)==0 | |
| 883 | + ){ | |
| 879 | 884 | db_begin_transaction(); |
| 880 | 885 | if( p->idTranscript==0 ) smtp_server_schema(0); |
| 881 | 886 | db_prepare(&s, |
| 882 | 887 | "INSERT INTO emailblob(ets,etime,etxt)" |
| 883 | 888 | " VALUES(:ets,now(),:etxt)" |
| @@ -920,25 +925,72 @@ | ||
| 920 | 925 | } |
| 921 | 926 | |
| 922 | 927 | /* |
| 923 | 928 | ** Make a copy of the input string up to but not including the |
| 924 | 929 | ** first ">" character. |
| 930 | +** | |
| 931 | +** Verify that the string really that is to be copied really is a | |
| 932 | +** valid email address. If it is not, then return NULL. | |
| 933 | +** | |
| 934 | +** This routine is more restrictive than necessary. It does not | |
| 935 | +** allow comments, IP address, quoted strings, or certain uncommon | |
| 936 | +** characters. The only non-alphanumerics allowed in the local | |
| 937 | +** part are "_", "+", "-" and "+". | |
| 925 | 938 | */ |
| 926 | 939 | static char *extractEmail(const char *z){ |
| 927 | 940 | int i; |
| 928 | - for(i=0; z[i] && z[i]!='>'; i++){} | |
| 941 | + int nAt = 0; | |
| 942 | + int nDot = 0; | |
| 943 | + char c; | |
| 944 | + if( z[0]=='.' ) return 0; /* Local part cannot begin with "." */ | |
| 945 | + for(i=0; (c = z[i])!=0 && c!='>'; i++){ | |
| 946 | + if( fossil_isalnum(c) ){ | |
| 947 | + /* Alphanumerics are always ok */ | |
| 948 | + }else if( c=='@' ){ | |
| 949 | + if( nAt ) return 0; /* Only a single "@" allowed */ | |
| 950 | + if( i>64 ) return 0; /* Local part too big */ | |
| 951 | + nAt = 1; | |
| 952 | + nDot = 0; | |
| 953 | + if( i==0 ) return 0; /* Disallow empty local part */ | |
| 954 | + if( z[i-1]=='.' ) return 0; /* Last char of local cannot be "." */ | |
| 955 | + if( z[i+1]=='.' || z[i+1]=='-' ){ | |
| 956 | + return 0; /* Domain cannot begin with "." or "-" */ | |
| 957 | + } | |
| 958 | + }else if( c=='-' ){ | |
| 959 | + if( z[i+1]=='>' ) return 0; /* Last character cannot be "-" */ | |
| 960 | + }else if( c=='.' ){ | |
| 961 | + if( z[i+1]=='.' ) return 0; /* Do not allow ".." */ | |
| 962 | + if( z[i+1]=='>' ) return 0; /* Domain may not end with . */ | |
| 963 | + nDot++; | |
| 964 | + }else if( (c=='_' || c=='+') && nAt==0 ){ | |
| 965 | + /* _ and + are ok in the local part */ | |
| 966 | + }else{ | |
| 967 | + return 0; /* Anything else is an error */ | |
| 968 | + } | |
| 969 | + } | |
| 970 | + if( c!='>' ) return 0; /* Missing final ">" */ | |
| 971 | + if( nAt==0 ) return 0; /* No "@" found anywhere */ | |
| 972 | + if( nDot==0 ) return 0; /* No "." in the domain */ | |
| 973 | + | |
| 974 | + /* If we reach this point, the email address is valid */ | |
| 929 | 975 | return mprintf("%.*s", i, z); |
| 930 | 976 | } |
| 931 | 977 | |
| 932 | 978 | /* |
| 933 | 979 | ** COMMAND: smtpd |
| 934 | 980 | ** |
| 935 | 981 | ** Usage: %fossil smtpd [OPTIONS] REPOSITORY |
| 936 | 982 | ** |
| 937 | 983 | ** Begin a SMTP conversation with a client using stdin/stdout. The |
| 938 | -** received email is stored in REPOSITORY | |
| 984 | +** received email is stored in REPOSITORY. | |
| 985 | +** | |
| 986 | +** Options: | |
| 987 | +** | |
| 988 | +** --dryrun Do not record any emails in the database | |
| 939 | 989 | ** |
| 990 | +** --trace Print a transcript of the conversation on stderr | |
| 991 | +** for debugging and analysis | |
| 940 | 992 | */ |
| 941 | 993 | void smtp_server(void){ |
| 942 | 994 | char *zDbName; |
| 943 | 995 | const char *zDomain; |
| 944 | 996 | SmtpServer x; |
| @@ -947,50 +999,68 @@ | ||
| 947 | 999 | smtp_server_init(&x); |
| 948 | 1000 | zDomain = find_option("domain",0,1); |
| 949 | 1001 | if( zDomain==0 ) zDomain = ""; |
| 950 | 1002 | x.srvrFlags = SMTPSRV_LOG; |
| 951 | 1003 | if( find_option("trace",0,0)!=0 ) x.srvrFlags |= SMTPSRV_STDERR; |
| 1004 | + if( find_option("dryrun",0,0)!=0 ) x.srvrFlags |= SMTPSRV_DRYRUN; | |
| 952 | 1005 | verify_all_options(); |
| 953 | 1006 | if( g.argc!=3 ) usage("DBNAME"); |
| 954 | 1007 | zDbName = g.argv[2]; |
| 955 | 1008 | zDbName = enter_chroot_jail(zDbName, 0); |
| 956 | 1009 | db_open_repository(zDbName); |
| 957 | 1010 | smtp_server_send(&x, "220 %s ESMTP https://fossil-scm.org/ %s\r\n", |
| 958 | 1011 | zDomain, MANIFEST_VERSION); |
| 959 | 1012 | while( smtp_server_gets(&x, z, sizeof(z)) ){ |
| 960 | - if( strncmp(z, "EHLO ", 5)==0 ){ | |
| 1013 | + if( strncmp(z, "EHLO", 4)==0 && fossil_isspace(z[4]) ){ | |
| 961 | 1014 | smtp_server_send(&x, "250 ok\r\n"); |
| 962 | 1015 | }else |
| 963 | - if( strncmp(z, "HELO ", 5)==0 ){ | |
| 1016 | + if( strncmp(z, "HELO", 4)==0 && fossil_isspace(z[4]) ){ | |
| 964 | 1017 | smtp_server_send(&x, "250 ok\r\n"); |
| 965 | 1018 | }else |
| 966 | 1019 | if( strncmp(z, "MAIL FROM:<", 11)==0 ){ |
| 967 | 1020 | smtp_server_route_incoming(&x, 0); |
| 968 | 1021 | smtp_server_clear(&x, SMTPSRV_CLEAR_MSG); |
| 969 | 1022 | x.zFrom = extractEmail(z+11); |
| 970 | - smtp_server_send(&x, "250 ok\r\n"); | |
| 1023 | + if( x.zFrom==0 ){ | |
| 1024 | + smtp_server_send(&x, "500 unacceptable email address\r\n"); | |
| 1025 | + }else{ | |
| 1026 | + smtp_server_send(&x, "250 ok\r\n"); | |
| 1027 | + } | |
| 971 | 1028 | }else |
| 972 | 1029 | if( strncmp(z, "RCPT TO:<", 9)==0 ){ |
| 973 | - char *zAddr = extractEmail(z+9); | |
| 1030 | + char *zAddr; | |
| 1031 | + if( x.zFrom==0 ){ | |
| 1032 | + smtp_server_send(&x, "500 missing MAIL FROM\r\n"); | |
| 1033 | + continue; | |
| 1034 | + } | |
| 1035 | + zAddr = extractEmail(z+9); | |
| 1036 | + if( zAddr==0 ){ | |
| 1037 | + smtp_server_send(&x, "505 no such user\r\n"); | |
| 1038 | + continue; | |
| 1039 | + } | |
| 974 | 1040 | smtp_append_to(&x, zAddr, 0); |
| 975 | 1041 | if( x.nTo>=100 ){ |
| 976 | 1042 | smtp_server_send(&x, "452 too many recipients\r\n"); |
| 977 | 1043 | continue; |
| 978 | 1044 | } |
| 979 | 1045 | smtp_server_send(&x, "250 ok\r\n"); |
| 980 | 1046 | }else |
| 981 | - if( strncmp(z, "DATA", 4)==0 ){ | |
| 1047 | + if( strncmp(z, "DATA", 4)==0 && fossil_isspace(z[4]) ){ | |
| 1048 | + if( x.zFrom==0 || x.nTo==0 ){ | |
| 1049 | + smtp_server_send(&x, "500 missing RCPT TO\r\n"); | |
| 1050 | + continue; | |
| 1051 | + } | |
| 982 | 1052 | smtp_server_send(&x, "354 ready\r\n"); |
| 983 | 1053 | smtp_server_capture_data(&x, z, sizeof(z)); |
| 984 | 1054 | smtp_server_send(&x, "250 ok\r\n"); |
| 985 | 1055 | }else |
| 986 | - if( strncmp(z, "QUIT", 4)==0 ){ | |
| 1056 | + if( strncmp(z, "QUIT", 4)==0 && fossil_isspace(z[4]) ){ | |
| 987 | 1057 | smtp_server_send(&x, "221 closing connection\r\n"); |
| 1058 | + smtp_server_route_incoming(&x, 1); | |
| 988 | 1059 | break; |
| 989 | 1060 | }else |
| 990 | 1061 | { |
| 991 | 1062 | smtp_server_send(&x, "500 unknown command\r\n"); |
| 992 | 1063 | } |
| 993 | 1064 | } |
| 994 | - smtp_server_route_incoming(&x, 1); | |
| 995 | 1065 | smtp_server_clear(&x, SMTPSRV_CLEAR_ALL); |
| 996 | 1066 | } |
| 997 | 1067 |
| --- src/smtp.c | |
| +++ src/smtp.c | |
| @@ -688,10 +688,11 @@ | |
| 688 | |
| 689 | #define SMTPSRV_CLEAR_MSG 1 /* smtp_server_clear() last message only */ |
| 690 | #define SMTPSRV_CLEAR_ALL 2 /* smtp_server_clear() everything */ |
| 691 | #define SMTPSRV_LOG 0x001 /* Record a transcript of the interaction */ |
| 692 | #define SMTPSRV_STDERR 0x002 /* Transcription written to stderr */ |
| 693 | |
| 694 | #endif /* LOCAL_INTERFACE */ |
| 695 | |
| 696 | /* |
| 697 | ** Clear the SmtpServer object. Deallocate resources. |
| @@ -873,11 +874,15 @@ | |
| 873 | ** Add this email to the database. |
| 874 | */ |
| 875 | static void smtp_server_route_incoming(SmtpServer *p, int bFinish){ |
| 876 | Stmt s; |
| 877 | int i, j; |
| 878 | if( p->zFrom && p->nTo && blob_size(&p->msg) ){ |
| 879 | db_begin_transaction(); |
| 880 | if( p->idTranscript==0 ) smtp_server_schema(0); |
| 881 | db_prepare(&s, |
| 882 | "INSERT INTO emailblob(ets,etime,etxt)" |
| 883 | " VALUES(:ets,now(),:etxt)" |
| @@ -920,25 +925,72 @@ | |
| 920 | } |
| 921 | |
| 922 | /* |
| 923 | ** Make a copy of the input string up to but not including the |
| 924 | ** first ">" character. |
| 925 | */ |
| 926 | static char *extractEmail(const char *z){ |
| 927 | int i; |
| 928 | for(i=0; z[i] && z[i]!='>'; i++){} |
| 929 | return mprintf("%.*s", i, z); |
| 930 | } |
| 931 | |
| 932 | /* |
| 933 | ** COMMAND: smtpd |
| 934 | ** |
| 935 | ** Usage: %fossil smtpd [OPTIONS] REPOSITORY |
| 936 | ** |
| 937 | ** Begin a SMTP conversation with a client using stdin/stdout. The |
| 938 | ** received email is stored in REPOSITORY |
| 939 | ** |
| 940 | */ |
| 941 | void smtp_server(void){ |
| 942 | char *zDbName; |
| 943 | const char *zDomain; |
| 944 | SmtpServer x; |
| @@ -947,50 +999,68 @@ | |
| 947 | smtp_server_init(&x); |
| 948 | zDomain = find_option("domain",0,1); |
| 949 | if( zDomain==0 ) zDomain = ""; |
| 950 | x.srvrFlags = SMTPSRV_LOG; |
| 951 | if( find_option("trace",0,0)!=0 ) x.srvrFlags |= SMTPSRV_STDERR; |
| 952 | verify_all_options(); |
| 953 | if( g.argc!=3 ) usage("DBNAME"); |
| 954 | zDbName = g.argv[2]; |
| 955 | zDbName = enter_chroot_jail(zDbName, 0); |
| 956 | db_open_repository(zDbName); |
| 957 | smtp_server_send(&x, "220 %s ESMTP https://fossil-scm.org/ %s\r\n", |
| 958 | zDomain, MANIFEST_VERSION); |
| 959 | while( smtp_server_gets(&x, z, sizeof(z)) ){ |
| 960 | if( strncmp(z, "EHLO ", 5)==0 ){ |
| 961 | smtp_server_send(&x, "250 ok\r\n"); |
| 962 | }else |
| 963 | if( strncmp(z, "HELO ", 5)==0 ){ |
| 964 | smtp_server_send(&x, "250 ok\r\n"); |
| 965 | }else |
| 966 | if( strncmp(z, "MAIL FROM:<", 11)==0 ){ |
| 967 | smtp_server_route_incoming(&x, 0); |
| 968 | smtp_server_clear(&x, SMTPSRV_CLEAR_MSG); |
| 969 | x.zFrom = extractEmail(z+11); |
| 970 | smtp_server_send(&x, "250 ok\r\n"); |
| 971 | }else |
| 972 | if( strncmp(z, "RCPT TO:<", 9)==0 ){ |
| 973 | char *zAddr = extractEmail(z+9); |
| 974 | smtp_append_to(&x, zAddr, 0); |
| 975 | if( x.nTo>=100 ){ |
| 976 | smtp_server_send(&x, "452 too many recipients\r\n"); |
| 977 | continue; |
| 978 | } |
| 979 | smtp_server_send(&x, "250 ok\r\n"); |
| 980 | }else |
| 981 | if( strncmp(z, "DATA", 4)==0 ){ |
| 982 | smtp_server_send(&x, "354 ready\r\n"); |
| 983 | smtp_server_capture_data(&x, z, sizeof(z)); |
| 984 | smtp_server_send(&x, "250 ok\r\n"); |
| 985 | }else |
| 986 | if( strncmp(z, "QUIT", 4)==0 ){ |
| 987 | smtp_server_send(&x, "221 closing connection\r\n"); |
| 988 | break; |
| 989 | }else |
| 990 | { |
| 991 | smtp_server_send(&x, "500 unknown command\r\n"); |
| 992 | } |
| 993 | } |
| 994 | smtp_server_route_incoming(&x, 1); |
| 995 | smtp_server_clear(&x, SMTPSRV_CLEAR_ALL); |
| 996 | } |
| 997 |
| --- src/smtp.c | |
| +++ src/smtp.c | |
| @@ -688,10 +688,11 @@ | |
| 688 | |
| 689 | #define SMTPSRV_CLEAR_MSG 1 /* smtp_server_clear() last message only */ |
| 690 | #define SMTPSRV_CLEAR_ALL 2 /* smtp_server_clear() everything */ |
| 691 | #define SMTPSRV_LOG 0x001 /* Record a transcript of the interaction */ |
| 692 | #define SMTPSRV_STDERR 0x002 /* Transcription written to stderr */ |
| 693 | #define SMTPSRV_DRYRUN 0x004 /* Do not record anything in database */ |
| 694 | |
| 695 | #endif /* LOCAL_INTERFACE */ |
| 696 | |
| 697 | /* |
| 698 | ** Clear the SmtpServer object. Deallocate resources. |
| @@ -873,11 +874,15 @@ | |
| 874 | ** Add this email to the database. |
| 875 | */ |
| 876 | static void smtp_server_route_incoming(SmtpServer *p, int bFinish){ |
| 877 | Stmt s; |
| 878 | int i, j; |
| 879 | if( p->zFrom |
| 880 | && p->nTo |
| 881 | && blob_size(&p->msg) |
| 882 | && (p->srvrFlags & SMTPSRV_DRYRUN)==0 |
| 883 | ){ |
| 884 | db_begin_transaction(); |
| 885 | if( p->idTranscript==0 ) smtp_server_schema(0); |
| 886 | db_prepare(&s, |
| 887 | "INSERT INTO emailblob(ets,etime,etxt)" |
| 888 | " VALUES(:ets,now(),:etxt)" |
| @@ -920,25 +925,72 @@ | |
| 925 | } |
| 926 | |
| 927 | /* |
| 928 | ** Make a copy of the input string up to but not including the |
| 929 | ** first ">" character. |
| 930 | ** |
| 931 | ** Verify that the string really that is to be copied really is a |
| 932 | ** valid email address. If it is not, then return NULL. |
| 933 | ** |
| 934 | ** This routine is more restrictive than necessary. It does not |
| 935 | ** allow comments, IP address, quoted strings, or certain uncommon |
| 936 | ** characters. The only non-alphanumerics allowed in the local |
| 937 | ** part are "_", "+", "-" and "+". |
| 938 | */ |
| 939 | static char *extractEmail(const char *z){ |
| 940 | int i; |
| 941 | int nAt = 0; |
| 942 | int nDot = 0; |
| 943 | char c; |
| 944 | if( z[0]=='.' ) return 0; /* Local part cannot begin with "." */ |
| 945 | for(i=0; (c = z[i])!=0 && c!='>'; i++){ |
| 946 | if( fossil_isalnum(c) ){ |
| 947 | /* Alphanumerics are always ok */ |
| 948 | }else if( c=='@' ){ |
| 949 | if( nAt ) return 0; /* Only a single "@" allowed */ |
| 950 | if( i>64 ) return 0; /* Local part too big */ |
| 951 | nAt = 1; |
| 952 | nDot = 0; |
| 953 | if( i==0 ) return 0; /* Disallow empty local part */ |
| 954 | if( z[i-1]=='.' ) return 0; /* Last char of local cannot be "." */ |
| 955 | if( z[i+1]=='.' || z[i+1]=='-' ){ |
| 956 | return 0; /* Domain cannot begin with "." or "-" */ |
| 957 | } |
| 958 | }else if( c=='-' ){ |
| 959 | if( z[i+1]=='>' ) return 0; /* Last character cannot be "-" */ |
| 960 | }else if( c=='.' ){ |
| 961 | if( z[i+1]=='.' ) return 0; /* Do not allow ".." */ |
| 962 | if( z[i+1]=='>' ) return 0; /* Domain may not end with . */ |
| 963 | nDot++; |
| 964 | }else if( (c=='_' || c=='+') && nAt==0 ){ |
| 965 | /* _ and + are ok in the local part */ |
| 966 | }else{ |
| 967 | return 0; /* Anything else is an error */ |
| 968 | } |
| 969 | } |
| 970 | if( c!='>' ) return 0; /* Missing final ">" */ |
| 971 | if( nAt==0 ) return 0; /* No "@" found anywhere */ |
| 972 | if( nDot==0 ) return 0; /* No "." in the domain */ |
| 973 | |
| 974 | /* If we reach this point, the email address is valid */ |
| 975 | return mprintf("%.*s", i, z); |
| 976 | } |
| 977 | |
| 978 | /* |
| 979 | ** COMMAND: smtpd |
| 980 | ** |
| 981 | ** Usage: %fossil smtpd [OPTIONS] REPOSITORY |
| 982 | ** |
| 983 | ** Begin a SMTP conversation with a client using stdin/stdout. The |
| 984 | ** received email is stored in REPOSITORY. |
| 985 | ** |
| 986 | ** Options: |
| 987 | ** |
| 988 | ** --dryrun Do not record any emails in the database |
| 989 | ** |
| 990 | ** --trace Print a transcript of the conversation on stderr |
| 991 | ** for debugging and analysis |
| 992 | */ |
| 993 | void smtp_server(void){ |
| 994 | char *zDbName; |
| 995 | const char *zDomain; |
| 996 | SmtpServer x; |
| @@ -947,50 +999,68 @@ | |
| 999 | smtp_server_init(&x); |
| 1000 | zDomain = find_option("domain",0,1); |
| 1001 | if( zDomain==0 ) zDomain = ""; |
| 1002 | x.srvrFlags = SMTPSRV_LOG; |
| 1003 | if( find_option("trace",0,0)!=0 ) x.srvrFlags |= SMTPSRV_STDERR; |
| 1004 | if( find_option("dryrun",0,0)!=0 ) x.srvrFlags |= SMTPSRV_DRYRUN; |
| 1005 | verify_all_options(); |
| 1006 | if( g.argc!=3 ) usage("DBNAME"); |
| 1007 | zDbName = g.argv[2]; |
| 1008 | zDbName = enter_chroot_jail(zDbName, 0); |
| 1009 | db_open_repository(zDbName); |
| 1010 | smtp_server_send(&x, "220 %s ESMTP https://fossil-scm.org/ %s\r\n", |
| 1011 | zDomain, MANIFEST_VERSION); |
| 1012 | while( smtp_server_gets(&x, z, sizeof(z)) ){ |
| 1013 | if( strncmp(z, "EHLO", 4)==0 && fossil_isspace(z[4]) ){ |
| 1014 | smtp_server_send(&x, "250 ok\r\n"); |
| 1015 | }else |
| 1016 | if( strncmp(z, "HELO", 4)==0 && fossil_isspace(z[4]) ){ |
| 1017 | smtp_server_send(&x, "250 ok\r\n"); |
| 1018 | }else |
| 1019 | if( strncmp(z, "MAIL FROM:<", 11)==0 ){ |
| 1020 | smtp_server_route_incoming(&x, 0); |
| 1021 | smtp_server_clear(&x, SMTPSRV_CLEAR_MSG); |
| 1022 | x.zFrom = extractEmail(z+11); |
| 1023 | if( x.zFrom==0 ){ |
| 1024 | smtp_server_send(&x, "500 unacceptable email address\r\n"); |
| 1025 | }else{ |
| 1026 | smtp_server_send(&x, "250 ok\r\n"); |
| 1027 | } |
| 1028 | }else |
| 1029 | if( strncmp(z, "RCPT TO:<", 9)==0 ){ |
| 1030 | char *zAddr; |
| 1031 | if( x.zFrom==0 ){ |
| 1032 | smtp_server_send(&x, "500 missing MAIL FROM\r\n"); |
| 1033 | continue; |
| 1034 | } |
| 1035 | zAddr = extractEmail(z+9); |
| 1036 | if( zAddr==0 ){ |
| 1037 | smtp_server_send(&x, "505 no such user\r\n"); |
| 1038 | continue; |
| 1039 | } |
| 1040 | smtp_append_to(&x, zAddr, 0); |
| 1041 | if( x.nTo>=100 ){ |
| 1042 | smtp_server_send(&x, "452 too many recipients\r\n"); |
| 1043 | continue; |
| 1044 | } |
| 1045 | smtp_server_send(&x, "250 ok\r\n"); |
| 1046 | }else |
| 1047 | if( strncmp(z, "DATA", 4)==0 && fossil_isspace(z[4]) ){ |
| 1048 | if( x.zFrom==0 || x.nTo==0 ){ |
| 1049 | smtp_server_send(&x, "500 missing RCPT TO\r\n"); |
| 1050 | continue; |
| 1051 | } |
| 1052 | smtp_server_send(&x, "354 ready\r\n"); |
| 1053 | smtp_server_capture_data(&x, z, sizeof(z)); |
| 1054 | smtp_server_send(&x, "250 ok\r\n"); |
| 1055 | }else |
| 1056 | if( strncmp(z, "QUIT", 4)==0 && fossil_isspace(z[4]) ){ |
| 1057 | smtp_server_send(&x, "221 closing connection\r\n"); |
| 1058 | smtp_server_route_incoming(&x, 1); |
| 1059 | break; |
| 1060 | }else |
| 1061 | { |
| 1062 | smtp_server_send(&x, "500 unknown command\r\n"); |
| 1063 | } |
| 1064 | } |
| 1065 | smtp_server_clear(&x, SMTPSRV_CLEAR_ALL); |
| 1066 | } |
| 1067 |