Index: ossp-pkg/lmtp2nntp/lmtp2nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v rcsdiff -q -kk '-r1.14' '-r1.15' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v' 2>/dev/null --- lmtp2nntp.c 2001/08/13 06:41:41 1.14 +++ lmtp2nntp.c 2001/08/13 15:16:32 1.15 @@ -640,6 +640,7 @@ char errorstring[STDSTRLEN]; char *rcpt; int i; + int bSuccess; if (argz_count(ctx->msg->azRcpt, ctx->msg->asRcpt) == 0) { res.statuscode = "503"; @@ -738,18 +739,27 @@ } } - for (i=0; i < ctx->nsc; i++) { + bSuccess = FALSE; + for (i = 0; i < ctx->nsc; i++) { fprintf(stderr, "DEBUG: trying service %s\n", ctx->ns[i].h); - (void)nntp_post(ctx->ns[i].nntp, ctx->msg); + if (nntp_post(ctx->ns[i].nntp, ctx->msg) == NNTP_OK) + bSuccess = TRUE; } rcpt = NULL; while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) { - res.statuscode = "250"; - res.dsncode = "2.0.0"; - str_format(errorstring, sizeof(errorstring), "Message accepted for delivery to %s", rcpt); - res.statusmsg = errorstring; - lmtp_response(lmtp, &res); + if (bSuccess == TRUE) { + res.statuscode = "250"; + res.dsncode = "2.0.0"; + str_format(errorstring, sizeof(errorstring), "Message accepted for delivery to %s", rcpt); + res.statusmsg = errorstring; + lmtp_response(lmtp, &res); + } else { + res.statuscode = "500"; + res.dsncode = "5.0.0"; + res.statusmsg = "Error posting message."; //FIXME call nntp_error()? + lmtp_response(lmtp, &res); + } } msg_destroy(ctx->msg); Index: ossp-pkg/lmtp2nntp/msg.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/msg.c,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/msg.c,v' 2>/dev/null --- msg.c 2001/08/13 06:41:41 1.1 +++ msg.c 2001/08/13 15:16:32 1.2 @@ -127,6 +127,11 @@ msg->asNewsgroups = 0; cp = msg->azHeaders; while (cp != NULL) { + if (strcasecmp("From", cp) == 0) { + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */ + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */ + continue; + } if (strcasecmp("To:", cp) == 0) { argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */ argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */ @@ -183,6 +188,8 @@ char *cpCut; char *cpWrap; char *cpNew; + char c; + int n; /* verify asNewsgroups */ if (msg->azNewsgroups == NULL) @@ -287,13 +294,68 @@ argz_stringify(msg->azBody, msg->asBody, '\n'); msg->cpBody = msg->azBody; - if ((msg->cpMsg = malloc(strlen(msg->cpHeaders) + 1 + strlen(msg->cpBody) + 2 + 1)) == NULL) + /******************************************************************** + * header + CRLF + body + '.' + CRLF + '\0', replacing NL with CRLF * + ********************************************************************/ + + n = 0; + /* count size of headers, reserve space for NL to CRLF conversion */ + for (i = 0; ((c = msg->cpHeaders[i]) != '\0'); i++) { + if (c == '\n') + n++; + n++; + } + /* if headers don't end with NL, reserve space for CRLF */ + if (i >= 0 && msg->cpHeaders[i - 1] != '\n') + n+=2; + /* reserve space for CRLF between headers and body */ + n+=2; + /* count size of body, reserve space for NL to CRLF conversion */ + for (i = 0; ((c = msg->cpBody[i]) != '\0'); i++) { + if (c == '\n') + n++; + n++; + } + /* if body doesn't end with NL, reserve space for CRLF */ + if (i >= 0 && msg->cpBody[i - 1] != '\n') + n+=2; + /* reserve space for terminating '.'-CRLF-NUL at the end of the message */ + n+=4; + + if ((msg->cpMsg = (char *)malloc(n)) == NULL) return MSG_ERR_MEM; - *msg->cpMsg = '\0'; /* + 1 in the end */ - strcat(msg->cpMsg, msg->cpHeaders); - strcat(msg->cpMsg, "\n"); /* + 1 */ - strcat(msg->cpMsg, msg->cpBody); - strcat(msg->cpMsg, ".\n"); /* + 2 */ + + n = 0; + /* copy headers, do NL to CRLF conversion */ + for (i = 0; ((c = msg->cpHeaders[i]) != '\0'); i++) { + if (c == '\n') + msg->cpMsg[n++] = '\r'; + msg->cpMsg[n++] = c; + } + /* if headers don't end with NL, append CRLF */ + if (i >= 0 && msg->cpHeaders[i - 1] != '\n') { + msg->cpMsg[n++] = '\r'; + msg->cpMsg[n++] = '\n'; + } + /* add CRLF between headers and body */ + msg->cpMsg[n++] = '\r'; + msg->cpMsg[n++] = '\n'; + /* copy body, do NL to CRLF conversion */ + for (i = 0; ((c = msg->cpBody[i]) != '\0'); i++) { + if (c == '\n') + msg->cpMsg[n++] = '\r'; + msg->cpMsg[n++] = c; + } + /* if body doesn't end with NL, append CRLF */ + if (i >= 0 && msg->cpBody[i - 1] != '\n') { + msg->cpMsg[n++] = '\r'; + msg->cpMsg[n++] = '\n'; + } + /* add terminating '.'-CRLF-NUL at the end of the message */ + msg->cpMsg[n++] = '.'; + msg->cpMsg[n++] = '\r'; + msg->cpMsg[n++] = '\n'; + msg->cpMsg[n] = '\0'; //fprintf(stderr, "DEBUG: Message = ***%s***\n", msg->cpMsg); Index: ossp-pkg/lmtp2nntp/nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.c,v rcsdiff -q -kk '-r1.4' '-r1.5' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.c,v' 2>/dev/null --- nntp.c 2001/08/13 06:41:42 1.4 +++ nntp.c 2001/08/13 15:16:32 1.5 @@ -182,7 +182,7 @@ buf[n] = '\0'; /* string termination */ if (n == (buflen-1)) return NNTP_ERR_OVERFLOW; - fprintf(stderr, "DEBUG: nntp_readline >>>%s\n", buf); + fprintf(stderr, "DEBUG: nntp_readline <<<%s\n", buf); return NNTP_OK; } @@ -205,11 +205,57 @@ nntp_rc_t rc = NNTP_OK; char line[NNTP_LINE_MAXLEN]; + /* RFC 2980 + * + * 2.3 MODE READER + * MODE READER is used by the client to indicate to the server that it is + * a news reading client. Some implementations make use of this + * information to reconfigure themselves for better performance in + * responding to news reader commands. This command can be contrasted + * with the SLAVE command in RFC 977, which was not widely implemented. + * MODE READER was first available in INN. + * + * 2.3.1 Responses + * 200 Hello, you can post + * 201 Hello, you can't post + * + * Research: + * + * < 200 dev16 InterNetNews server INN 2.3.2 ready + * > POST + * < 500 "post" not implemented; try "help". + * > MODE READER + * < 200 dev16 InterNetNews NNRP server INN 2.3.2 ready (posting ok). + * > POST + * < 340 Ok, recommended ID <...> + * + * In other words, INN *requires* the use of "MODE READER". + */ + *line = '\0'; + strcat(line, "MODE READER"); + if ((rc = nntp_writeline(nntp, line)) != NNTP_OK) + return rc; + if ((rc = nntp_readline(nntp, line, sizeof(line))) != NNTP_OK) + return rc; + + /* A 200 response means posting ok, 201 means posting not allowed. We + * don't care about 5xx errors, they simply mean the server doesn't know + * about the RFC2980 "MODE READER" command. But any other response is not + * expected and we treat this as an error. + */ + if (strncmp(line, "201", 3) == 0) + return NNTP_ERR_POST; + if ( strncmp(line, "200", 3) != 0 + && strncmp(line, "5" , 1) != 0 + ) + return NNTP_ERR_POST; + /* check if this server already knows that artice * > STAT * < 223 yes, article already known * < 430 no, i don't know the article, yet */ +#if 0 *line = '\0'; strcat(line, "STAT "); strcat(line, msg->cpMsgid); @@ -220,7 +266,8 @@ if (strncmp(line, "223", 3) == 0) return NNTP_OK; if (strncmp(line, "430", 3) != 0) - return NNTP_ERR_POSTPERM; //FIXME + return NNTP_ERR_POST; +#endif /* post the article * > POST @@ -235,10 +282,22 @@ * > . * < 240 ok, thank you * < 441 duplicate (ok for us) + * + * Research: + * + * < 200 dev16 InterNetNews server INN 2.3.2 ready + * > POST + * [...] + * 240 Article posted <...> + * 441 435 Duplicate + * 441 437 Too old + * 441 Duplicate "Newsgroups" header + * 441 Required "Subject" header is missing + * + * In other words, INN uses 441 for other status messages as well. */ *line = '\0'; - strcat(line, "POST "); - strcat(line, msg->cpMsgid); + strcat(line, "POST"); if ((rc = nntp_writeline(nntp, line)) != NNTP_OK) return rc; if ((rc = nntp_readline(nntp, line, sizeof(line))) != NNTP_OK) @@ -246,33 +305,19 @@ if (strncmp(line, "xxx", 3) == 0) return NNTP_OK; if (strncmp(line, "340", 3) != 0) - return NNTP_ERR_POSTPERM; //FIXME + return NNTP_ERR_POST; -fprintf(stderr, "DEBUG: before write ***%s***(%d)\n", msg->cpMsg, strlen(msg->cpMsg)); - if ((rc = nntp->io.write(nntp->wfd, msg->cpMsg, strlen(msg->cpMsg))) < 0) + if ((rc = nntp->io.write(nntp->wfd, msg->cpMsg, strlen(msg->cpMsg))) < 0) //FIXME while() wrapper around write required return NNTP_ERR_SYSTEM; -fprintf(stderr, "DEBUG: after write, written = %i\n", rc); - {//DEBUG paragraph - int i; - char buf[NNTP_LINE_MAXLEN]; - - fprintf(stderr, "DEBUG: before writeline\n"); - if ((rc = nntp_writeline(nntp, "\r\n.\r\nHELP\r\n")) != NNTP_OK); - fprintf(stderr, "DEBUG: writeline returned %d\n", rc); - - fprintf(stderr, "DEBUG: before io.read(%d, ..., %d)\n", nntp->rfd, NNTP_LINE_MAXLEN); - i = nntp->io.read(nntp->rfd, &buf, NNTP_LINE_MAXLEN); - fprintf(stderr, "DEBUG: io.read = ***%s***, rc = %d\n", buf, i); - - - for (i=0; i<10; i++) { if ((rc = nntp_readline(nntp, line, sizeof(line))) != NNTP_OK) - ; //return rc; + return rc; fprintf(stderr, "DEBUG: answer to post = ***%s***, rc = %s\n", line, nntp_error(nntp, rc)); - }; - } - return NNTP_OK; + if ( (strncmp(line, "240", 3) == 0) + || (strncmp(line, "441", 3) == 0) + ) + return NNTP_OK; + return NNTP_ERR_POST; #if 0 /* check if this server accepts at least one of the newsgroups @@ -294,6 +339,7 @@ else if (rc == NNTP_ERR_SYSTEM ) str = "NNTP: see errno"; else if (rc == NNTP_ERR_ARG ) str = "NNTP: invalid argument"; else if (rc == NNTP_ERR_OVERFLOW) str = "NNTP: buffer overflow"; + else if (rc == NNTP_ERR_POST ) str = "NNTP: cannot post message"; return str; } Index: ossp-pkg/lmtp2nntp/nntp.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.h,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.h,v' 2>/dev/null --- nntp.h 2001/08/13 06:41:42 1.3 +++ nntp.h 2001/08/13 15:16:32 1.4 @@ -52,7 +52,7 @@ NNTP_ERR_SYSTEM, NNTP_ERR_ARG, NNTP_ERR_OVERFLOW, - NNTP_ERR_POSTPERM, + NNTP_ERR_POST, NNTP_ERR_POSTDEFER, NNTP_ERR_INIT } nntp_rc_t; Index: ossp-pkg/lmtp2nntp/test/run.sh RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/test/Attic/run.sh,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/test/Attic/run.sh,v' 2>/dev/null --- run.sh 2001/08/08 10:40:43 1.1 +++ run.sh 2001/08/13 15:16:32 1.2 @@ -6,12 +6,19 @@ fi echo ------------------------------------------------------------ #./lmtp2nntp -h news-muc1.de.cw.net -h news-ffm2.de.cw.net -h news-dus2.de.cw.net -h news-ecrc.de -awk \" } \ !/Message-ID/ { print \$0 } \ " \ - | ./lmtp2nntp -g envelope -h news-ffm2.de.cw.net -h news-dus2.de.cw.net -h news.ecrc.de + | tee /tmp/reusetestmessage \ + | ./lmtp2nntp -g envelope -h dev16 +cat /tmp/reusetestmessage | ./lmtp2nntp -g envelope -h dev16 echo ----------------------------------------------------------- +exit + if [ -r /tmp/t ] then cat /tmp/t