OSSP CVS Repository

ossp - Check-in [610]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 610
Date: 2001-Aug-07 11:05:55 (local)
2001-Aug-07 09:05:55 (UTC)
User:thl
Branch:
Comment: lmtp/nntp joined at command args and lhlo
Tickets:
Inspections:
Files:
ossp-pkg/lmtp2nntp/lmtp2nntp.c      1.8 -> 1.9     141 inserted, 64 deleted
ossp-pkg/lmtp2nntp/lmtp2nntp.pod      1.3 -> 1.4     10 inserted, 18 deleted
ossp-pkg/lmtp2nntp/nntp.c      1.2 -> 1.3     38 inserted, 9 deleted
ossp-pkg/lmtp2nntp/nntp.h      1.1 -> 1.2     6 inserted, 1 deleted

ossp-pkg/lmtp2nntp/lmtp2nntp.c 1.8 -> 1.9

--- 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 <SP> <domain> <CRLF>
      */
     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)
 {


ossp-pkg/lmtp2nntp/lmtp2nntp.pod 1.3 -> 1.4

--- 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<protocol>]
 [B<-l> I<logtarget>]
 [B<-h> I<host>[I<:port>]]
-[B<-d> I<deliverymode>]
 [B<-g> I<groupmode>]
 [B<-t>]
 [B<-v>]
@@ -66,23 +65,16 @@
 
 =item B<-h> I<host>[:<port>]
 
-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<NNTPSERVER> is read, if this is undefined or empty C<news> is
-used and if this doesn't resolve, C<localhost> is assumed. This
-option can be specified more than once. The program connects to the
-services in given order.
-
-=item B<-d> I<deliverymode>
-
-Possible values for I<deliverymode> are C<many> (default), C<once> and
-C<full>. This option is only useful when multiple NNTP servers are given. In
-C<many> mode, the program posts to as many servers as it can. Sucessfully
-posting the message one or more times returns success. In I<once> mode it
-stops processing immediately after the first successful delivery and returns
-success. In I<full> 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<NNTPSERVER> is read, if this is
+undefined or empty C<news> is used and if this doesn't resolve, C<localhost>
+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<groupmode>
 


ossp-pkg/lmtp2nntp/nntp.c 1.2 -> 1.3

--- 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 <unistd.h>
 #include <ctype.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
 
 #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";


ossp-pkg/lmtp2nntp/nntp.h 1.1 -> 1.2

--- 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 *);

CVSTrac 2.0.1