Index: ossp-pkg/lmtp2nntp/lmtp2nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v rcsdiff -q -kk '-r1.8' '-r1.9' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v' 2>/dev/null --- lmtp2nntp.c 2001/08/02 14:58:39 1.8 +++ lmtp2nntp.c 2001/08/07 09:05:55 1.9 @@ -23,7 +23,7 @@ /* own headers */ #include "lmtp.h" #include "nntp.h" -#include "sock.h" +#include "sa.h" #ifndef FALSE #define FALSE (1 != 1) @@ -37,6 +37,7 @@ #define MESSAGE_MAXLEN 8*1024*1024 #define STDSTRLEN 128 +#define MAXNEWSSERVICES 3 extern void lmtp_debug_dumplmtp(lmtp_t *lmtp); @@ -69,11 +70,20 @@ }; static void resetmessage(struct message *message); +struct newsservice { + char *h; /* host */ + char *p; /* port */ + sa_t *sa; + int s; /* socket */ + nntp_t *nntp; +}; + typedef struct { int option_verbose; int option_tracing; - int option_deliverymode; int option_groupmode; + int newsservicecount; + struct newsservice newsservice[MAXNEWSSERVICES]; char *azArggroups; size_t asArggroups; struct session session; @@ -81,12 +91,6 @@ } lmtp2nntp_t; enum { - DELIVERYMODE_ONCE, - DELIVERYMODE_MANY, - DELIVERYMODE_FULL -}; - -enum { GROUPMODE_ARG, GROUPMODE_ENVELOPE, GROUPMODE_HEADER @@ -141,18 +145,13 @@ lmtp2nntp_t *ctx; int i; /* general purpose scratch int, index ... */ char *progname; + char *cpHost; + char *cpPort; + sa_t *sa; #if 0 /* begin NNTP posting test */ { - int s; - nntp_t *nntp; - - if ((s = sock_create(argv[1])) == -1) { - fprintf(stderr, "fuck socket\n"); - exit(1); - } - nntp = nntp_create(s, s, NULL); nntp_post(nntp, "..."); nntp_destroy(nntp); sock_destroy(s); @@ -167,8 +166,13 @@ exit(ERR_EXECUTION); ctx->option_verbose = FALSE; ctx->option_tracing = FALSE; - ctx->option_deliverymode = DELIVERYMODE_MANY; ctx->option_groupmode = GROUPMODE_ARG; + ctx->newsservicecount = 0; + for (i=0; i < MAXNEWSSERVICES; i++) { + ctx->newsservice[i].h = ""; + ctx->newsservice[i].s = -1; + ctx->newsservice[i].nntp = NULL; + } ctx->azArggroups = NULL; ctx->asArggroups = 0; resetsession(&ctx->session); @@ -188,20 +192,8 @@ } /* read in the arguments */ - while ((i = getopt(argc, argv, "d:g:tv")) != -1) { + while ((i = getopt(argc, argv, "g:h:tv")) != -1) { switch (i) { - 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 'g': /* -g groupmode */ if (strcasecmp(optarg, "arg") == 0) ctx->option_groupmode = GROUPMODE_ARG; @@ -214,6 +206,47 @@ exit(ERR_EXECUTION); } break; + case 'h': /* -h host */ + if (ctx->newsservicecount >= MAXNEWSSERVICES) { + fprintf(stderr, "%s:Error: Too many services (%d) using option -h\n", progname, ctx->newsservicecount); + exit(ERR_EXECUTION); + } + + /* parse host[:port] string into host and port */ + cpHost = strdup(optarg); + if ((cpPort = strrchr(cpHost, ':')) != NULL) { + *cpPort++ = '\0'; + cpPort = strdup(cpPort); + } + else + cpPort = strdup("nntp"); + ctx->newsservice[ctx->newsservicecount].h = cpHost; + ctx->newsservice[ctx->newsservicecount].p = cpPort; + + if ((sa = sa_create(SA_IP, "tcp", + ctx->newsservice[ctx->newsservicecount].h, + ctx->newsservice[ctx->newsservicecount].p)) == NULL) { + fprintf(stderr, "%s:Error: creating TCP socket address failed for \"%s:%s\": %s\n", + progname, + ctx->newsservice[ctx->newsservicecount].h, + ctx->newsservice[ctx->newsservicecount].p, + strerror(errno)); + exit(ERR_EXECUTION); + } + if ((ctx->newsservice[ctx->newsservicecount].s = + socket(sa->sa_buf->sa_family, SOCK_STREAM, sa->sa_proto)) == -1) { + fprintf(stderr, "%s:Error: Creating TCP socket failed for \"%s:%s\": %s\n", + progname, + ctx->newsservice[ctx->newsservicecount].h, + ctx->newsservice[ctx->newsservicecount].p, + strerror(errno)); + exit(ERR_EXECUTION); + } + ctx->newsservice[ctx->newsservicecount].sa = sa; + //FIXME sa_destroy(sa); + ctx->newsservice[ctx->newsservicecount].nntp = NULL; + ctx->newsservicecount++; + break; case 't': // -t (tracing) ctx->option_tracing = TRUE; break; @@ -309,37 +342,84 @@ * HELO */ lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx; - lmtp_rc_t rc = LMTP_OK; lmtp_res_t res; + nntp_rc_t rc; char str[STDSTRLEN]; + int bOk; + int i; if (ctx->session.lhlo_seen == TRUE) { res.statuscode = "503"; res.dsncode = "5.0.0"; res.statusmsg = "Duplicate LHLO."; - } else { - 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. Domain must match RFC0821/RFC1035."; + lmtp_response(lmtp, &res); + return LMTP_OK; + } + + if (! ( helo_rfc0821domain(req->msg, &ctx->session.lhlo_domain) + || helo_rfc1035domain(req->msg, &ctx->session.lhlo_domain) + )) { + res.statuscode = "501"; + res.dsncode = "5.0.0"; + res.statusmsg = "Please identify yourself. Domain must match RFC0821/RFC1035."; + lmtp_response(lmtp, &res); + return LMTP_OK; + } + + if (ctx->newsservicecount == 0) { + res.statuscode = "501"; + res.dsncode = "5.0.0"; + res.statusmsg = "No valid NNTP Services specified."; + lmtp_response(lmtp, &res); + return LMTP_OK; + } + + i = 0; + do { + bOk = TRUE; + if (connect(ctx->newsservice[i].s, ctx->newsservice[i].sa->sa_buf, ctx->newsservice[i].sa->sa_len) < 0) { + fprintf(stderr, "DEBUG: connect failed: %s\n", strerror(errno)); + bOk = FALSE; + } + if (bOk && ((ctx->newsservice[i].nntp = nntp_create(ctx->newsservice[i].s, ctx->newsservice[i].s, NULL)) == NULL)) { + fprintf(stderr, "DEBUG: nntp_create failed: %s\n", strerror(errno)); + bOk = FALSE; + } + if (bOk && ((rc = nntp_init(ctx->newsservice[i].nntp)) != NNTP_OK)) { + fprintf(stderr, "DEBUG: nntp_init failed: %s\n", nntp_error(ctx->newsservice[i].nntp, rc)); + bOk = FALSE; + } + if (bOk) + i++; + else { + if (i < --ctx->newsservicecount) { + memcpy(&ctx->newsservice[i], &ctx->newsservice[i+1], (ctx->newsservicecount - i ) * sizeof(struct newsservice)); + } } + } while (i < ctx->newsservicecount); + + if (ctx->newsservicecount == 0) { + res.statuscode = "501"; + res.dsncode = "5.0.0"; + res.statusmsg = "No connection to any NNTP Service."; //FIXME add error strings from above DEBUGs + lmtp_response(lmtp, &res); + return LMTP_OK; } + + ctx->session.lhlo_seen = TRUE; + 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.statuscode = "250"; + res.dsncode = NULL; /* DSN not used for greeting */ + res.statusmsg = str; lmtp_response(lmtp, &res); - return rc; + return LMTP_OK; } static int helo_rfc0821domain(char *msg, char **domain) @@ -494,7 +574,6 @@ static lmtp_rc_t lmtp_cb_rcpt(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx) { - lmtp_rc_t rc = LMTP_OK; lmtp_res_t res; lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx; char *cp; @@ -525,7 +604,7 @@ if (ctx->option_groupmode == GROUPMODE_ENVELOPE) { // fprintf(stderr, "DEBUG: before transform cp=***%s***\n", cp); - if (!str_parse(cp, "m/^.+?\\+(.+)?@.+$/i", &group)) { + if (!str_parse(cp, "m/^.+?\\+(.+)?@.+$/i", &group)) { //FIXME >=2 * @ res.statuscode = "550"; res.dsncode = "5.1.1"; res.statusmsg = "Recipient did not transform into Group."; @@ -543,7 +622,7 @@ return LMTP_OK; } } - + if ((cp == NULL) || (strlen(cp) == 0)) { res.statuscode = "550"; res.dsncode = "5.1.1"; @@ -551,17 +630,15 @@ 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; -} + // 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 LMTP_OK; +} static lmtp_rc_t lmtp_cb_data(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx) { Index: ossp-pkg/lmtp2nntp/lmtp2nntp.pod RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/lmtp2nntp.pod,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/lmtp2nntp.pod,v' 2>/dev/null --- lmtp2nntp.pod 2001/08/02 14:58:39 1.3 +++ lmtp2nntp.pod 2001/08/07 09:05:55 1.4 @@ -15,7 +15,6 @@ [B<-p> I] [B<-l> I] [B<-h> I[I<:port>]] -[B<-d> I] [B<-g> I] [B<-t>] [B<-v>] @@ -66,23 +65,16 @@ =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<-d> I - -Possible values for I are C (default), C and -C. This option is only useful when multiple NNTP servers are given. In -C mode, the program 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. In I mode successful posting to all newservers is required to -return successful. +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. It is assumed that multiple +servers are used to increase the reliability of the news system and to speed +up distribution by posting the same article to more than one server. In regard +to this program they must provide the same groups and talk to each other. =item B<-g> I Index: ossp-pkg/lmtp2nntp/nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.c,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.c,v' 2>/dev/null --- nntp.c 2001/08/02 14:58:39 1.2 +++ nntp.c 2001/08/07 09:05:55 1.3 @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "nntp.h" @@ -50,22 +52,24 @@ int wfd; nntp_io_t io; nntp_readline_t rl; + struct timeval tv; }; nntp_t *nntp_create(int rfd, int wfd, nntp_io_t *io) { nntp_t *nntp; - char line[NNTP_LINE_MAXLEN]; if ((nntp = (nntp_t *)malloc(sizeof(nntp_t))) == NULL) return NULL; if (io == NULL) { - nntp->io.read = read; - nntp->io.write = write; + nntp->io.select = select; + nntp->io.read = read; + nntp->io.write = write; } else { - nntp->io.read = io->read ? io->read : read; - nntp->io.write = io->write ? io->write : write; + nntp->io.select = io->select ? io->select : select; + nntp->io.read = io->read ? io->read : read; + nntp->io.write = io->write ? io->write : write; } nntp->rfd = rfd; @@ -73,14 +77,22 @@ nntp->rl.rl_cnt = 0; nntp->rl.rl_bufptr = NULL; nntp->rl.rl_buf[0] = '\0'; + nntp_timeout(nntp, 3); return nntp; } -#if 0 //FIXME +nntp_rc_t nntp_timeout(nntp_t *nntp, long timeout) +{ + nntp->tv.tv_sec = timeout; + nntp->tv.tv_usec = 0; + return NNTP_OK; +} + nntp_rc_t nntp_init(nntp_t *nntp) { nntp_rc_t rc; + char line[NNTP_LINE_MAXLEN]; /* RFC0977 2.4.3. General Responses * In general, 1xx codes may be ignored or displayed as desired; code 200 @@ -101,15 +113,19 @@ */ do { - if ((rc = nntp_readline(nntp, line, sizeof(line))) != NNTP_OK) + if ((rc = nntp_readline(nntp, line, sizeof(line))) != NNTP_OK) { + fprintf(stderr, "DEBUG: nntp_readline returned ***%d***\n", rc); return rc; - while (line[0] == '1'); + } + } while (line[0] == '1'); + + // fprintf(stderr, "DEBUG: nntp_readline got ***%s***\n", line); + if (strncmp(line, "200", 3) == 0) return NNTP_OK; return NNTP_ERR_INIT; } -#endif void nntp_destroy(nntp_t *nntp) { @@ -124,6 +140,9 @@ size_t n; char c; nntp_readline_t *rl = &nntp->rl; + struct timeval tv; + fd_set fds; + int rc; if (nntp == NULL) return NNTP_ERR_ARG; @@ -131,6 +150,15 @@ /* fetch one character (but read more) */ if (rl->rl_cnt <= 0) { + FD_ZERO(&fds); + FD_SET(nntp->rfd, &fds); + tv.tv_sec = nntp->tv.tv_sec; + tv.tv_usec = nntp->tv.tv_usec; + rc = nntp->io.select(nntp->rfd + 1, &fds, NULL, NULL, &tv); + if (rc == 0) + return NNTP_TIMEOUT; + else if (rc == -1) + return NNTP_ERR_SYSTEM; do { rl->rl_cnt = nntp->io.read(nntp->rfd, rl->rl_buf, NNTP_LINE_MAXLEN); } while (rl->rl_cnt == -1 && errno == EINTR); @@ -240,6 +268,7 @@ str = "NNTP: errorcode has no description"; if (rc == NNTP_OK ) str = "NNTP: no error"; else if (rc == NNTP_EOF ) str = "NNTP: end of file"; + else if (rc == NNTP_TIMEOUT ) str = "NNTP: timeout"; 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"; Index: ossp-pkg/lmtp2nntp/nntp.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.h,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.h,v' 2>/dev/null --- nntp.h 2001/08/01 07:04:13 1.1 +++ nntp.h 2001/08/07 09:05:56 1.2 @@ -39,6 +39,7 @@ typedef struct nntp_st nntp_t; typedef struct { + int (*select)(int, fd_set *, fd_set *, fd_set *, struct timeval *); ssize_t (*read)(int, void *, size_t); ssize_t (*write)(int, const void *, size_t); } nntp_io_t; @@ -46,12 +47,16 @@ typedef enum { NNTP_OK, NNTP_EOF, + NNTP_TIMEOUT, NNTP_ERR_SYSTEM, NNTP_ERR_ARG, - NNTP_ERR_OVERFLOW + NNTP_ERR_OVERFLOW, + NNTP_ERR_INIT } nntp_rc_t; nntp_t *nntp_create (int, int, nntp_io_t *); +nntp_rc_t nntp_timeout (nntp_t *nntp, long); +nntp_rc_t nntp_init (nntp_t *); void nntp_destroy (nntp_t *); nntp_rc_t nntp_readline (nntp_t *, char *, size_t); nntp_rc_t nntp_writeline(nntp_t *, char *);