Index: ossp-pkg/lmtp2nntp/.cvsignore RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/.cvsignore,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/.cvsignore,v' 2>/dev/null --- .cvsignore 2001/07/16 12:18:09 1.1 +++ .cvsignore 2001/07/17 12:40:06 1.2 @@ -1,2 +1,2 @@ -mail2nntp +lmtp2nntp research Index: ossp-pkg/lmtp2nntp/00TODO RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/00TODO,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/00TODO,v' 2>/dev/null --- 00TODO 2001/07/16 12:12:21 1.1 +++ 00TODO 2001/07/17 12:40:06 1.2 @@ -3,13 +3,42 @@ RESULT: - robust checking and handling of NNTP protocol errors -- logging into a single file -> write(2) !fwrite(3) + - logging into a single file -> write(2) !fwrite(3) - invoked as mailer using LMTP, providing useful return status - invoked as command line (lowpri) - queuing is not supported for command line and a client issue for LMTP - remove To: and Cc: headers - allow crosspostings only through command line - new manpage -- (optional) syslog + - (optional) syslog - command line choice for sending "exactly once" or "at least once" (default) + **** SMTP ENGINE **** + +[RFC821, 4.5.1. MINIMUM IMPLEMENTATION] +In order to make SMTP workable, the following minimum implementation is required for all receivers: +[RFC821, 4.1.2. COMMAND SYNTAX] + +Verb Parameter Buffer +----+---------------------------------+------------------- +HELO +MAIL FROM: (char *)sender +RCPT TO: (char **)recipients +DATA (char *)message +RSET +NOOP +QUIT + + +State Function Continue +-----+--------+----------------- + 0 wait() LHLO > 1, MAIL > 2 + 1 wait() MAIL > 2 + 2 wait() RCPT > 3 + 3 wait() RCPT > 3, DATA > 4 + 4 data() >1 + + x wait() RSET > 1 + x wait() NOOP > x + x wait() QUIT > exit + Index: ossp-pkg/lmtp2nntp/lmtp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.c,v' | diff -u /dev/null - -L'ossp-pkg/lmtp2nntp/lmtp.c' 2>/dev/null --- ossp-pkg/lmtp2nntp/lmtp.c +++ - 2024-04-20 16:18:37.968485510 +0200 @@ -0,0 +1,128 @@ + +#include + +#include "lmtp.h" +#include "lmtp_p.h" + +static int readline(lmtp_readline_t *rl, int fd, char *buf, size_t buflen) +{ + size_t n; + ssize_t rc; + char c = '\0', *cp; + + cp = (char *)buf; + for (n = 1; n < buflen; n++) { + + /* fetch one character (but read more) */ + rc = 1; + if (rl->rl_cnt <= 0) { + if ((rl->rl_cnt = rl->rl_read(fd, rl->rl_buf, LMTP_READLINE_MAXLEN)) < 0) + rc = -1; + else if (rl->rl_cnt == 0) + rc = 0; + else + rl->rl_bufptr = rl->rl_buf; + } + if (rc == 1) { + rl->rl_cnt--; + c = *rl->rl_bufptr++; + } + + /* act on fetched character */ + if (rc == 1) { + if (c == '\r') { + n--; + continue; + } + *cp++ = c; + if (c == '\n') + break; + } + else if (rc == 0) { + if (n == 1) + return 0; + else + break; + } + else + return -1; + } + *cp = '\0'; + return n; +} + +lmtp_t *lmtp_create(int rfd, int wfd, lmtp_io_t *io) +{ + lmtp_t *lmtp = NULL; + + if ((lmtp = (lmtp_t *)malloc(sizeof(lmtp_t))) == NULL) + return NULL; + lmtp->io.select = select; + lmtp->io.read = read; + lmtp->io.write = write; + lmtp->rl.rl_cnt = 0; + lmtp->rl.rl_bufptr = NULL; + lmtp->rl.rl_read = lmtp->io.read; + /* lmtp->dispatch = ... */ + return lmtp; +} + +void lmtp_destroy(lmtp_t *lmtp) +{ + return; +} + +lmtp_rc_t lmtp_request(lmtp_t *lmtp, lmtp_req_t *req) +{ + lmtp_rc_t rc = LMTP_OK; + return rc; +} + +lmtp_rc_t lmtp_result(lmtp_t *lmtp, lmtp_res_t *res) +{ + lmtp_rc_t rc = LMTP_OK; + return rc; +} + +char **lmtp_message(lmtp_t *lmtp, char *verb) +{ + char **cpp = NULL; + return cpp; +} + +void lmtp_reset(lmtp_t *lmtp) +{ + return; +} + +char *lmtp_error(lmtp_t *lmtp, lmtp_rc_t rc) +{ + char *str = NULL; + return str; +} + +lmtp_cb_t lmtp_register(lmtp_t *lmtp, char *verb, lmtp_type_t type, lmtp_cb_t *cb, void *ctx) +{ + lmtp_cb_t old = NULL; + return old; +} + +lmtp_rc_t lmtp_loop(lmtp_t *lmtp) +{ + lmtp_req_t req; + lmtp_res_t res; + lmtp_rc_t rc; + int i; + + while ((rc = lmtp_request(lmtp, &req)) == LMTP_OK) { + for (i = 0; lmtp->dispatch[i]->verb != NULL; i++) { + if (strcmp(req.verb, lmtp->dispatch[i]->verb) == 0) { + lmtp->dispatch[i]->cb(&lmtp->io, &req, &res, lmtp->dispatch[i]->cbctx); + if ((rc = lmtp_result(lmtp, &res)) != LMTP_OK) + return rc; + } + } + } + return rc; +} + Index: ossp-pkg/lmtp2nntp/lmtp.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp.h,v' | diff -u /dev/null - -L'ossp-pkg/lmtp2nntp/lmtp.h' 2>/dev/null --- ossp-pkg/lmtp2nntp/lmtp.h +++ - 2024-04-20 16:18:37.971423771 +0200 @@ -0,0 +1,52 @@ +#ifndef __LMTP_H__ +#define __LMTP_H__ + +#include +#include +#include +#include + +struct lmtp_st; +typedef struct lmtp_st lmtp_t; + +typedef struct { + int (*select)(int nfds, fd_set *rfds, fd_set *wrfds, fd_set *efds, struct timeval *t); + ssize_t (*read) (int fd, void *buf, size_t nbytes); + ssize_t (*write) (int fd, const void *buf, size_t nbytes); +} lmtp_io_t; + +typedef struct { + char *verb; + char *msg; +} lmtp_req_t; + +typedef struct { + int rc; + char *dsn; + char *msg; +} lmtp_res_t; + +typedef enum { + LMTP_OK, + LMTP_ERR_SYSTEM, /* see errno */ + LMTP_ERR_INVALID_VERB +} lmtp_rc_t; + +typedef enum { + LMTP_TYPE_SINGLELINE, + LMTP_TYPE_MULTILINE +} lmtp_type_t; + +typedef lmtp_rc_t (*lmtp_cb_t)(lmtp_io_t *io, lmtp_req_t *req, lmtp_res_t *res, void *ctx); + +lmtp_t *lmtp_create (int rfd, int wfd, lmtp_io_t *io); +void lmtp_destroy (lmtp_t *lmtp); +lmtp_rc_t lmtp_request (lmtp_t *lmtp, lmtp_req_t *req); +lmtp_rc_t lmtp_result (lmtp_t *lmtp, lmtp_res_t *res); +char **lmtp_message (lmtp_t *lmtp, char *verb); +void lmtp_reset (lmtp_t *lmtp); +char *lmtp_error (lmtp_t *lmtp, lmtp_rc_t rc); +lmtp_cb_t lmtp_register(lmtp_t *lmtp, char *verb, lmtp_type_t type, lmtp_cb_t *cb, void *ctx); +lmtp_rc_t lmtp_loop (lmtp_t *lmtp); + +#endif /* __LMTP_H__ */ Index: ossp-pkg/lmtp2nntp/lmtp2nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v' | diff -u /dev/null - -L'ossp-pkg/lmtp2nntp/lmtp2nntp.c' 2>/dev/null --- ossp-pkg/lmtp2nntp/lmtp2nntp.c +++ - 2024-04-20 16:18:37.974133848 +0200 @@ -0,0 +1,66 @@ + +/* + * mail2nntp.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 OSSP Project, Cable & Wireless Deutschland GmbH + * Thomas Lotterer, + * + */ + +#include +#include + +#define ERR_EXECUTION -1 +#define ERR_DELIVERY -2 + +void usage(char *command); + +int main(int argc, char **argv) +{ + int i; // general purpose scratch int, index ... + + // read in the arguments + + while ((i = getopt(argc, argv, "p:l:h:m:tv")) != -1) + switch (i) { + case 'p': // -p protocol + break; + case 'l': // -l logtarget + break; + case 'h': // -h host[:port] + break; + case 'm': // -m mode + break; + case 'd': // -t (tracing) + break; + case 'v': // -v (verbose) + break; + case '?': + default: + usage(argv[0]); + exit(ERR_EXECUTION); + } + argc -= optind; argv += optind; // remaining args is/are newsgroup/s + + printf("Hello, World!\n"); + return 0; +} + +/* + * print usage information + * + */ + +void usage(char *command) +{ + fprintf(stderr, "USAGE: %s [-p protocol] [-l logtarget] "\ + "[-h host[:port]] [-m mode] [-t] [-v] newsgroup [newsgroup ...]\n", + command); + return; +} + Index: ossp-pkg/lmtp2nntp/lmtp2nntp.pod RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/lmtp2nntp.pod,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/lmtp2nntp/lmtp2nntp.pod,v' | diff -u /dev/null - -L'ossp-pkg/lmtp2nntp/lmtp2nntp.pod' 2>/dev/null --- ossp-pkg/lmtp2nntp/lmtp2nntp.pod +++ - 2024-04-20 16:18:37.978500152 +0200 @@ -0,0 +1,129 @@ + +=pod + +=head1 NAME + +B - mail to nntp gateway + +=head1 SYNOPSIS + +B +[B<-p> I] +[B<-l> I] +[B<-h> I[I<:port>]] +[B<-m> I] +[B<-t>] +[B<-v>] +I +[I ...] + +=head1 DESCRIPTION + +The B program reads mail from stdin and posts it to one or more +newsgroups using NNTP. It delivers the message immediately or fails. +If queuing is desired it can operate as a LMTP server. + +The following options are available: + +=over 4 + +=item B<-p> I + +Incoming protocol. Default is C which means B +reads the incoming mail from F in RFC822 message format and reports errors to F. +Alternatively if I is C, B speaks Local Mail +Transport Protocol (LMTP) according to RFC 2033 on F/F. + +=item B<-l> C + +=item B<-l> C[C<:>I] + +=item B<-l> CI + +Logging target. This option can be specified more than once. Default is no +logging. Default I for C is C. + +=item B<-h> I[:] + +Hostname or address and optional TCP port of a NNTP service. Unless a port +is specified, getserbyname(nntp) is queried with fallback to 119/tcp. If C<-h> +option is ommited, the environment +variable C is read, if this is undefined or empty C is +used and if this doesn't resolve, C is assumed. This +option can be specified more than once. The program connects to the +services in given order. + +=item B<-m> I + +Mode of delivery. Possible values for I are C (default) and +C. If multiple NNTP servers are given and running in C mode, it +posts to as many servers as it can. Sucessfully posting the message one or +more times returns success. In I mode it stops processing immediately +after the first successful delivery and returns success. + +=item B<-t> + +Enable LMTP protocol tracing in logfile. When using C these messages +are logged with C level. + +=item B<-v> + +Enable verbose processing messages in logfile. When using C these +messages are logged with C level. + +=item I + +Newsgroup to post the message to. Multiple groups can be specified. +Crosspostings only succeed if delivery to I groups succeed. + +=back + +=head1 SENDMAIL INTEGRATION + + Mlmtp2nntp, P=/... /*FIXME*/ + +=head1 EXAMPLE + + $ cat rfc822.message | lmtp2nntp -l /tmp/log -v -h mynews foo.bar + +reads rfc822.message and posts it into group "foo.bar" using NNTP service on +host "mynews". Activity is logged to /tmp/log. If posting is +successful, the exit status is 0. + + $ cat rfc822.message | lmtp2nntp -h news1 -h news2 -h news3 foo.bar + +reads rfc822.message and posts it into group "foo.bar" using NNTP service on +all hosts "news1", "news2" and "news3". Activtiy is not logged. +If at least one posting is successful, the exit status is 0. + + $ cat rfc822.message | lmtp2nntp -l stderr foo.bar quux.bar test.bar + +reads rfc822.message and posts it into groups "foo.bar", "quux.bar" and +"test.bar" using NNTP service on host C<${NNTPSERVER:-news}>. Activity +is logged to stderr. Only if all three crosspostings succeed, the exit +status is 0. + +=head1 DIAGNOSTICS + +when invoked from command line + + 0 = successful execution and delivery + 1 = execution failed + 2 = cannot deliver to any nntpserver + +when invoked as LMTP server + + 0 = successful execution + 1 = execution failed + +delivery status is part of the LMTP protocol + +=head1 AUTHOR + + The OSSP Project + Cable & Wireless Deutschland GmbH + Thomas Lotterer + + +=cut +