--- lmtp2nntp.c 2001/08/01 07:08:31 1.7
+++ lmtp2nntp.c 2001/08/02 14:58:39 1.8
@@ -1,17 +1,14 @@
/*
- * mail2nntp.c
+ * lmtp2nntp.c
*
- * The mail2nntp program reads mail from stdin and posts it
- * to one or more newsgroups using NNTP. It delivers the mes-
- * sage immediately or fails. If queuing is desired it can
- * operate as a LMTP server.
+ * The lmtp2nntp program reads mail as a LMTP server and posts it to one or
+ * more newsgroups using NNTP. It delivers the message immediately or fails.
*
* The OSSP Project, Cable & Wireless Deutschland GmbH
* Thomas Lotterer, <thomas.lotterer@cw.com>
*
*/
-
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
@@ -54,22 +51,45 @@
static lmtp_rc_t lmtp_cb_rset (lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
static lmtp_rc_t lmtp_cb_quit (lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx);
-typedef struct {
- int option_verbose;
- int option_tracing;
- int option_mode;
- char *azNewsgroups;
- size_t asNewsgroups;
- char *rfc822message;
+static int helo_rfc0821domain(char *msg, char **domain);
+static int helo_rfc1035domain(char *msg, char **domain);
+
+struct session {
int lhlo_seen;
char *lhlo_domain;
+};
+static void resetsession(struct session *session);
+
+
+struct message {
+ char *rfc822message;
+ char *mail_from;
char *azRcpt;
size_t asRcpt;
+};
+static void resetmessage(struct message *message);
+
+typedef struct {
+ int option_verbose;
+ int option_tracing;
+ int option_deliverymode;
+ int option_groupmode;
+ char *azArggroups;
+ size_t asArggroups;
+ struct session session;
+ struct message message;
} lmtp2nntp_t;
enum {
- MODE_ONCE,
- MODE_MANY
+ DELIVERYMODE_ONCE,
+ DELIVERYMODE_MANY,
+ DELIVERYMODE_FULL
+};
+
+enum {
+ GROUPMODE_ARG,
+ GROUPMODE_ENVELOPE,
+ GROUPMODE_HEADER
};
/*
@@ -115,13 +135,15 @@
int main(int argc, char **argv)
{
- int rc = 0;
+ //FIXME int rc = 0;
lmtp_t *lmtp;
lmtp_io_t lmtp_io;
lmtp2nntp_t *ctx;
- int i; /* general purpose scratch int, index ... */
+ int i; /* general purpose scratch int, index ... */
char *progname;
+#if 0
+ /* begin NNTP posting test */
{
int s;
nntp_t *nntp;
@@ -135,8 +157,8 @@
nntp_destroy(nntp);
sock_destroy(s);
exit(0);
-
}
+#endif
progname = argv[0];
@@ -145,16 +167,13 @@
exit(ERR_EXECUTION);
ctx->option_verbose = FALSE;
ctx->option_tracing = FALSE;
- ctx->option_mode = MODE_MANY;
- ctx->azNewsgroups = NULL;
- ctx->asNewsgroups = 0;
- ctx->rfc822message = NULL;
- ctx->lhlo_seen = FALSE;
- ctx->lhlo_domain = "";
- ctx->azRcpt = NULL;
- ctx->asRcpt = 0;
+ ctx->option_deliverymode = DELIVERYMODE_MANY;
+ ctx->option_groupmode = GROUPMODE_ARG;
+ ctx->azArggroups = NULL;
+ ctx->asArggroups = 0;
+ resetsession(&ctx->session);
+ resetmessage(&ctx->message);
- /* read in the arguments */
{
char buf[1000];
int bufused = 0;
@@ -167,33 +186,35 @@
close(tracefile);
}
}
- while ((i = getopt(argc, argv, "p:l:h:m:tvo:c:i:t:")) != -1) {
+
+ /* read in the arguments */
+ while ((i = getopt(argc, argv, "d:g:tv")) != -1) {
switch (i) {
- case 'p': // -p protocol
- break;
- case 'l': // -l logtarget
- break;
- case 'o': // FIXME
- break;
- case 'c': // FIXME
- break;
- case 'i': // FIXME
- break;
- case 't': // FIXME
- break;
- case 'h': // -h host[:port]
+ case 'd': /* -d deliverymode */
+ if (strcasecmp(optarg, "once") == 0)
+ ctx->option_deliverymode = DELIVERYMODE_ONCE;
+ else if (strcasecmp(optarg, "many") == 0)
+ ctx->option_deliverymode = DELIVERYMODE_MANY;
+ else if (strcasecmp(optarg, "full") == 0)
+ ctx->option_deliverymode = DELIVERYMODE_FULL;
+ else {
+ fprintf(stderr, "%s:Error: Invalid mode \"%s\" to option -d\n", progname, optarg);
+ exit(ERR_EXECUTION);
+ }
break;
- case 'm': // -m mode
- if (strcasecmp(argv[optind], "once") == 0)
- ctx->option_mode = MODE_ONCE;
- else if (strcasecmp(argv[optind], "many") == 0)
- ctx->option_mode = MODE_MANY;
+ case 'g': /* -g groupmode */
+ if (strcasecmp(optarg, "arg") == 0)
+ ctx->option_groupmode = GROUPMODE_ARG;
+ else if (strcasecmp(optarg, "envelope") == 0)
+ ctx->option_groupmode = GROUPMODE_ENVELOPE;
+ else if (strcasecmp(optarg, "header") == 0)
+ ctx->option_groupmode = GROUPMODE_HEADER;
else {
- fprintf(stderr, "%s:Error: Invalid mode \"%s\" to option -m\n", progname, argv[optind]);
+ fprintf(stderr, "%s:Error: Invalid mode \"%s\" to option -g\n", progname, optarg);
exit(ERR_EXECUTION);
}
break;
- case 'd': // -t (tracing)
+ case 't': // -t (tracing)
ctx->option_tracing = TRUE;
break;
case 'v': // -v (verbose)
@@ -205,9 +226,9 @@
exit(ERR_EXECUTION);
}
}
- /* remaining arguments are newsgroup names */
+ /* remaining arguments are groups */
for (i = optind; i < argc; i++)
- argz_add(&ctx->azNewsgroups, &ctx->asNewsgroups, argv[i]);
+ argz_add(&ctx->azArggroups, &ctx->asArggroups, argv[i]);
/* initialize LMTP context */
lmtp_io.read = trace_read;
@@ -230,6 +251,41 @@
return 0;
}
+static void resetsession(struct session *session)
+{
+
+ session->lhlo_seen = FALSE;
+
+ // fprintf(stderr, "DEBUG: session->lhlo_domain=***%s***\n", session->lhlo_domain);
+ if (session->lhlo_domain != NULL)
+ free(session->lhlo_domain); //FIXME what about non-graceful aborts?
+ session->lhlo_domain = NULL;
+
+ return;
+}
+
+static void resetmessage(struct message *message)
+{
+ // fprintf(stderr, "DEBUG: message->mail_from=***%s***\n", message->mail_from);
+ if (message->mail_from != NULL)
+ free(message->mail_from); //FIXME what about non-graceful aborts?
+ message->mail_from = NULL;
+
+ // fprintf(stderr, "DEBUG: message->azRcpt=***%s***\n", message->azRcpt);
+ if (message->azRcpt != NULL)
+ free(message->azRcpt); //FIXME what about non-graceful aborts?
+ message->azRcpt = NULL;
+
+ message->asRcpt = 0;
+
+ // fprintf(stderr, "DEBUG: message->rfc822message=***%s***\n", message->rfc822message);
+ if (message->rfc822message != NULL)
+ free(message->rfc822message); //FIXME what about non-graceful aborts?
+ message->rfc822message = NULL;
+
+ return;
+}
+
static lmtp_rc_t lmtp_cb_lhlo(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
{
/*
@@ -255,102 +311,150 @@
lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
lmtp_rc_t rc = LMTP_OK;
lmtp_res_t res;
- char errorstring[STDSTRLEN];
- char *cp;
+ char str[STDSTRLEN];
- cp = NULL;
- if (ctx->lhlo_seen == TRUE) {
+ if (ctx->session.lhlo_seen == TRUE) {
res.statuscode = "503";
res.dsncode = "5.0.0";
res.statusmsg = "Duplicate LHLO.";
} else {
- if (!str_parse(req->msg,
- "^.+ ("
-
- /*
- ##
- ## The mega Perl regular expression below is generated
- ## with the following Perl program. This is only possible
- ## because the given grammar is Chomsky-3 (right or left
- ## linear grammar, but noth both).
- ##
-
- # BNF grammar for <domain> according to RFC 821:
- # <snum> ::= one, two, or three digits representing a decimal integer value in the range 0 through 255
- # <a> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
- # <d> ::= any one of the ten digits 0 through 9
- # <let-dig-hyp> ::= <a> | <d> | "-"
- # <let-dig> ::= <a> | <d>
- # <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
- # <dotnum> ::= <snum> "." <snum> "." <snum> "." <snum>
- # <number> ::= <d> | <d> <number>
- # <name> ::= <a> <ldh-str> <let-dig>
- # <element> ::= <name> | "#" <number> | "[" <dotnum> "]"
- # <domain> ::= <element> | <element> "." <domain>
-
- FIXME # BNF grammar for <domain> according to RFC1035:
- # <letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
- # <digit> ::= any one of the ten digits 0 through 9
- # <let-dig> ::= <letter> | <digit>
- # <let-dig-hyp> ::= <let-dig> | "-"
- # <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
- # <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
- # <subdomain> ::= <label> | <subdomain> "." <label>
- # <domain> ::= <subdomain> | " "
-
- # corresponding Perl regular expression ($domain)
- $snum = "(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])";
- $d = "[0-9]";
- $a = "[A-Za-z]";
- $let_dig_hyp = "(?:$a|$d|-)";
- $let_dig = "(?:$a|$d)";
- $ldh_str = "${let_dig_hyp}+";
- $dotnum = "$snum\\.$snum\\.$snum\\.$snum";
- $number = "$d+";
- $name = "$a$ldh_str$let_dig";
- $element = "(?:$name|#$number|\\[$dotnum\\])";
- $domain = "(?:$element\.)*$element";
-
- # translate into C string block suitable for passing to the Perl
- # Compatible Regular Expressions (PCRE) based string library Str.
- my $cregex = $domain;
- $cregex =~ s|\\|\\\\|sg;
- $cregex =~ s|(.{70})|"$1"\n|sg;
- $cregex =~ s|\n([^\n]+)$|\n"$1"|s;
- print "$cregex\n";
- */
-
- "(?:(?:[A-Za-z](?:[A-Za-z]|[0-9]|-)+(?:[A-Za-z]|[0-9])|#[0-9]+|\\[(?:[0"
- "-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0"
- "-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0"
- "-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5"
- "])\\]).)*(?:[A-Za-z](?:[A-Za-z]|[0-9]|-)+(?:[A-Za-z]|[0-9])|#[0-9]+|\\"
- "[(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]"
- "{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{"
- "2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|"
- "25[0-5])\\])"
-
- ")$", &cp, &ctx->lhlo_domain)) {
+ if ( helo_rfc0821domain(req->msg, &ctx->session.lhlo_domain)
+ || helo_rfc1035domain(req->msg, &ctx->session.lhlo_domain)) {
+ ctx->session.lhlo_seen = TRUE;
+ res.statuscode = "250";
+ res.dsncode = NULL; /* DSN not used for greeting */
+ str_format(str, sizeof(str),
+ "FIXME.dev.de.cw.net" /* RFC2821 4.1.1.1 */
+ " Hello %s, pleased to meet you.\n"
+ "ENHANCEDSTATUSCODES\n" /* RFC2034 */
+ "DSN\n" /* RFC1894 */
+ "PIPELINING\n" /* RFC1854 */
+ "8BITMIME", /* RFC1652 */
+ ctx->session.lhlo_domain);
+ res.statusmsg = str;
+ } else {
res.statuscode = "501";
res.dsncode = "5.0.0";
- res.statusmsg = "Please identify yourself. See <domain> BNF in RFC821.";
- } else {
- ctx->lhlo_seen = TRUE;
- printf("DEBUG: cp=***%s***, v1=***%s***\n", cp, ctx->lhlo_domain);
- str_format(errorstring, sizeof(errorstring), "Hello ***%s***", ctx->lhlo_domain);
- res.statuscode = "250";
- res.dsncode = NULL; /* DSN not used for greeting */
- res.statusmsg = "ENHANCEDSTATUSCODES\nDSN\nPIPELINING\n8BITMIME";
- /*
- * RFC2034 = EHANCEDSTATUSCODES
- * RFC1894 = DSN
- * RFC1854 = PIPELINING
- * RFC1652 = 8BITMIME
- */
+ res.statusmsg = "Please identify yourself. Domain must match RFC0821/RFC1035.";
}
}
lmtp_response(lmtp, &res);
- if (cp) free(cp);
+ return rc;
+}
+
+static int helo_rfc0821domain(char *msg, char **domain)
+{
+ int rc;
+
+ rc = str_parse(msg,
+ "^.+ ("
+ /*
+ ##
+ ## The mega Perl regular expression below is generated
+ ## with the following Perl program. This is only possible
+ ## because the given grammar is Chomsky-3 (right or left
+ ## linear grammar, but noth both).
+ ##
+
+ # BNF grammar for <domain> according to RFC 821:
+ # <snum> ::= one, two, or three digits representing a decimal integer value in the range 0 through 255
+ # <a> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
+ # <d> ::= any one of the ten digits 0 through 9
+ # <let-dig-hyp> ::= <a> | <d> | "-"
+ # <let-dig> ::= <a> | <d>
+ # <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+ # <dotnum> ::= <snum> "." <snum> "." <snum> "." <snum>
+ # <number> ::= <d> | <d> <number>
+ # <name> ::= <a> <ldh-str> <let-dig>
+ # <element> ::= <name> | "#" <number> | "[" <dotnum> "]"
+ # <domain> ::= <element> | <element> "." <domain>
+ #
+ # corresponding Perl regular expression ($domain)
+ $snum = "(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])";
+ $d = "[0-9]";
+ $a = "[A-Za-z]";
+ $let_dig_hyp = "(?:$a|$d|-)";
+ $let_dig = "(?:$a|$d)";
+ $ldh_str = "${let_dig_hyp}+";
+ $dotnum = "$snum\\.$snum\\.$snum\\.$snum";
+ $number = "$d+";
+ $name = "$a$ldh_str$let_dig";
+ $element = "(?:$name|#$number|\\[$dotnum\\])";
+ $domain = "(?:$element\.)*$element";
+ #
+ # translate into C string block suitable for passing to the Perl
+ # Compatible Regular Expressions (PCRE) based string library Str.
+ my $cregex = $domain;
+ $cregex =~ s|\\|\\\\|sg;
+ $cregex =~ s|(.{70})|"$1"\n|sg;
+ $cregex =~ s|\n([^\n]+)$|\n"$1"|s; #FIXME this fails when last
+ #FIXME line matches linelength exacly
+ print "$cregex\n";
+ */
+
+ "(?:(?:[A-Za-z](?:[A-Za-z]|[0-9]|-)+(?:[A-Za-z]|[0-9])|#[0-9]+|\\[(?:[0"
+ "-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0"
+ "-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0"
+ "-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5"
+ "])\\]).)*(?:[A-Za-z](?:[A-Za-z]|[0-9]|-)+(?:[A-Za-z]|[0-9])|#[0-9]+|\\"
+ "[(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]"
+ "{2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{"
+ "2}|2[0-4][0-9]|25[0-5])\\.(?:[0-9]|[0-9]{2}|[0-1][0-9]{2}|2[0-4][0-9]|"
+ "25[0-5])\\])"
+
+ ")$", domain);
+ return rc;
+}
+
+static int helo_rfc1035domain(char *msg, char **domain)
+{
+ int rc;
+
+ rc = str_parse(msg,
+ "^.+ ("
+ /*
+ ##
+ ## The mega Perl regular expression below is generated
+ ## with the following Perl program. This is only possible
+ ## because the given grammar is Chomsky-3 (right or left
+ ## linear grammar, but noth both).
+ ##
+
+ # BNF grammar for <domain> according to RFC1035:
+ # <letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case
+ # <digit> ::= any one of the ten digits 0 through 9
+ # <let-dig> ::= <letter> | <digit>
+ # <let-dig-hyp> ::= <let-dig> | "-"
+ # <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+ # <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+ # <subdomain> ::= <label> | <subdomain> "." <label>
+ # <domain> ::= <subdomain> | " "
+ #
+ # corresponding Perl regular expression ($domain)
+ $letter = "[A-Za-z]";
+ $digit = "[0-9]";
+ $let_dig = "(?:$letter|$digit)";
+ $let_dig_hyp = "(?:$let_dig|-)";
+ $ldh_str = "${let_dig_hyp}+";
+ $label = "(?:$letter(?:(?:$ldh_str)?$let_dig)?)";
+ $subdomain = "(?:$label\.)*$label";
+ $domain = "(?:$subdomain| )";
+ #
+ # translate into C string block suitable for passing to the Perl
+ # Compatible Regular Expressions (PCRE) based string library Str.
+ my $cregex = $domain;
+ $cregex =~ s|\\|\\\\|sg;
+ $cregex =~ s|(.{70})|"$1"\n|sg;
+ $cregex =~ s|\n([^\n]+)$|\n"$1"|s; #FIXME this fails when last
+ #FIXME line matches linelength exacly
+ print "$cregex\n";
+ */
+
+ "(?:(?:(?:[A-Za-z](?:(?:(?:(?:[A-Za-z]|[0-9])|-)+)?(?:[A-Za-z]|[0-9]))?"
+ ").)*(?:[A-Za-z](?:(?:(?:(?:[A-Za-z]|[0-9])|-)+)?(?:[A-Za-z]|[0-9]))?)|"
+ " )"
+
+ ")$", domain);
return rc;
}
@@ -360,15 +464,29 @@
lmtp_rc_t rc = LMTP_OK;
lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
- if (ctx->lhlo_seen == TRUE) {
- res.statuscode = "250";
- res.dsncode = "2.1.0";
- res.statusmsg = "Sender ok FIXME";
- lmtp_response(lmtp, &res);
- } else {
+ if (ctx->session.lhlo_seen != TRUE) {
res.statuscode = "553";
res.dsncode = "5.1.8";
- res.statusmsg = "friendly people say LHLO to open a transmission channel";
+ res.statusmsg = "friendly people say LHLO to open a transmission channel.";
+ lmtp_response(lmtp, &res);
+ }
+ else if (ctx->message.mail_from != NULL) {
+ res.statuscode = "503";
+ res.dsncode = "5.5.0";
+ res.statusmsg = "Sender already specified.";
+ lmtp_response(lmtp, &res);
+ }
+ else
+ if (!str_parse(req->msg, "m/^MAIL From: <(.+@.+)>$/i", &ctx->message.mail_from)) {
+ res.statuscode = "553";
+ res.dsncode = "5.5.4";
+ res.statusmsg = "Domain name required for sender address.";
+ lmtp_response(lmtp, &res);
+ }
+ else {
+ res.statuscode = "250";
+ res.dsncode = "2.1.0";
+ res.statusmsg = "Sender ok.";
lmtp_response(lmtp, &res);
}
return rc;
@@ -379,13 +497,68 @@
lmtp_rc_t rc = LMTP_OK;
lmtp_res_t res;
lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
+ char *cp;
+ char *group;
- argz_add(&ctx->azRcpt, &ctx->asRcpt, req->msg);
- res.statuscode = "250";
- res.dsncode = "2.1.5";
- res.statusmsg = "Recipient ok FIXME";
- lmtp_response(lmtp, &res);
+ if (ctx->message.mail_from == NULL) {
+ res.statuscode = "503";
+ res.dsncode = "5.0.0";
+ res.statusmsg = "specify sender with MAIL first.";
+ lmtp_response(lmtp, &res);
+ return LMTP_OK;
+ }
+ if (!str_parse(req->msg, "m/^RCPT To: (.+)$/i", &cp)) {
+ res.statuscode = "501";
+ res.dsncode = "5.5.2";
+ res.statusmsg = "Syntax error in parameters.";
+ lmtp_response(lmtp, &res);
+ return LMTP_OK;
+ }
+
+ /* FIXME
+ * in GROUPMODE = ARG|HEADER recipient must be acknowledged and stored to
+ * give proper pipelining responses. in GROUPMODE = ENVELOPE recipient is
+ * transformed into a group and matched against groupfilter. Only valid
+ * groups are stored to give proper pipelining responses.
+ */
+
+ if (ctx->option_groupmode == GROUPMODE_ENVELOPE) {
+ // fprintf(stderr, "DEBUG: before transform cp=***%s***\n", cp);
+ if (!str_parse(cp, "m/^.+?\\+(.+)?@.+$/i", &group)) {
+ res.statuscode = "550";
+ res.dsncode = "5.1.1";
+ res.statusmsg = "Recipient did not transform into Group.";
+ lmtp_response(lmtp, &res);
+ return LMTP_OK;
+ }
+ cp = group;
+ // fprintf(stderr, "DEBUG: after transform cp=***%s***\n", cp);
+ //FIXME do additional transform and checking
+ if (0) {
+ res.statuscode = "550";
+ res.dsncode = "5.1.1";
+ res.statusmsg = "unmatched Group.";
+ lmtp_response(lmtp, &res);
+ return LMTP_OK;
+ }
+ }
+
+ if ((cp == NULL) || (strlen(cp) == 0)) {
+ res.statuscode = "550";
+ res.dsncode = "5.1.1";
+ res.statusmsg = "nul Recipient/ Group.";
+ lmtp_response(lmtp, &res);
+ return LMTP_OK;
+ }
+ else {
+ // fprintf(stderr, "DEBUG: cp=***%s***\n", cp);
+ argz_add(&ctx->message.azRcpt, &ctx->message.asRcpt, cp);
+ res.statuscode = "250";
+ res.dsncode = "2.1.5";
+ res.statusmsg = "Recipient/ Group accepted";
+ lmtp_response(lmtp, &res);
+ }
return rc;
}
@@ -399,6 +572,14 @@
char errorstring[STDSTRLEN];
char *rcpt;
+ if (argz_count(ctx->message.azRcpt, ctx->message.asRcpt) == 0) {
+ res.statuscode = "503";
+ res.dsncode = "5.0.0";
+ res.statusmsg = "specify recipient with RCPT first.";
+ lmtp_response(lmtp, &res);
+ return LMTP_OK;
+ }
+
res.statuscode = "354";
res.dsncode = NULL; /* DSN not used for data */
res.statusmsg = "Enter mail, end with \".\" on a line by itself";
@@ -406,28 +587,26 @@
rc = lmtp_readmsg(lmtp, &buf, MESSAGE_MAXLEN);
rcpt = NULL;
- while ((rcpt = argz_next(ctx->azRcpt, ctx->asRcpt, rcpt)) != NULL)
+ while ((rcpt = argz_next(ctx->message.azRcpt, ctx->message.asRcpt, rcpt)) != NULL)
{
if(rc == LMTP_OK) {
res.statuscode = "250";
res.dsncode = "2.0.0";
- // res.statusmsg = "Message accepted for delivery";
- str_format(errorstring, sizeof(errorstring),
- "Message accepted for delivery to %s", rcpt);
+ str_format(errorstring, sizeof(errorstring), "Message accepted for delivery to %s", rcpt);
res.statusmsg = errorstring;
} else if (rc == LMTP_ERR_OVERFLOW) {
res.statuscode = "500";
res.dsncode = "5.0.0";
- res.statusmsg = "Message accepted for delivery";
+ res.statusmsg = "FIXME overflow";
} else if (rc == LMTP_ERR_SYSTEM) {
res.statuscode = "500";
res.dsncode = "5.0.0";
- str_format(errorstring, sizeof(errorstring),
- "Message accepted for delivery %s", strerror(errno));
+ str_format(errorstring, sizeof(errorstring), "Message accepted for delivery %s", strerror(errno));
res.statusmsg = errorstring;
}
lmtp_response(lmtp, &res);
}
+ resetmessage(&ctx->message);
return rc;
}
@@ -435,33 +614,36 @@
{
lmtp_res_t res;
lmtp_rc_t rc = LMTP_OK;
+
res.statuscode = "250";
res.dsncode = "2.0.0";
- res.statusmsg = "OK";
+ res.statusmsg = "OK. Nice talking to you.";
lmtp_response(lmtp, &res);
return rc;
}
+
static lmtp_rc_t lmtp_cb_rset(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
{
lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
lmtp_res_t res;
lmtp_rc_t rc = LMTP_OK;
- if (ctx->azRcpt != NULL) {
- free(ctx->azRcpt);
- ctx->azRcpt = NULL;
- ctx->asRcpt = 0;
- }
+ resetmessage(&ctx->message);
res.statuscode = "250";
res.dsncode = "2.0.0";
res.statusmsg = "Reset state.";
lmtp_response(lmtp, &res);
return rc;
}
-static lmtp_rc_t lmtp_cb_quit(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx)
+
+static lmtp_rc_t lmtp_cb_quit(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx)
{
+ lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx;
lmtp_res_t res;
lmtp_rc_t rc = LMTP_EOF;
+
+ resetmessage(&ctx->message);
+ resetsession(&ctx->session);
res.statuscode = "221";
res.dsncode = "2.0.0";
res.statusmsg = "LMTP Service closing transmission channel.";
|