Index: ossp-pkg/lmtp2nntp/lmtp2nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v rcsdiff -q -kk '-r1.13' '-r1.14' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/lmtp2nntp.c,v' 2>/dev/null --- lmtp2nntp.c 2001/08/08 10:43:00 1.13 +++ lmtp2nntp.c 2001/08/13 06:41:41 1.14 @@ -24,6 +24,7 @@ #include "lmtp.h" #include "nntp.h" #include "sa.h" +#include "msg.h" #ifndef FALSE #define FALSE (1 != 1) @@ -52,8 +53,6 @@ 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); -static lmtp_rc_t prepareheader(void *ctx); - static int helo_rfc0821domain(char *msg, char **domain); static int helo_rfc1035domain(char *msg, char **domain); @@ -65,19 +64,6 @@ static void initsession(struct session *session); static void resetsession(struct session *session); -struct message { - char *cpMsg; /* the wholly message to be received by DATA command */ - char *cpHeaders; /* header part of message above */ - char *cpBody; /* body part of message above */ - char *mail_from; - char *azRcpt; - size_t asRcpt; - char *azHeaders; - size_t asHeaders; -}; -static void initmessage(struct message *message); -static void resetmessage(struct message *message); - struct ns { char *h; /* host */ char *p; /* port */ @@ -97,7 +83,7 @@ char *azGroupfilters; size_t asGroupfilters; struct session session; - struct message message; + msg_t *msg; } lmtp2nntp_t; enum { @@ -188,7 +174,7 @@ ctx->azGroupfilters = NULL; ctx->asGroupfilters = 0; initsession(&ctx->session); - initmessage(&ctx->message); + ctx->msg = NULL; { char buf[1000]; @@ -315,38 +301,6 @@ return; } -static void resetmessage(struct message *message) -{ - //FIXME what about non-graceful aborts? - if (message->mail_from != NULL) - free(message->mail_from); - if (message->azRcpt != NULL) - free(message->azRcpt); - if (message->azHeaders != NULL) - free(message->azHeaders); - if (message->cpMsg != NULL) - free(message->cpMsg); - if (message->cpHeaders != NULL) - free(message->cpHeaders); - if (message->cpBody != NULL) - free(message->cpBody); - initmessage(message); - return; -} - -static void initmessage(struct message *message) -{ - message->mail_from = NULL; - message->azRcpt = NULL; - message->asRcpt = 0; - message->azHeaders = NULL; - message->asHeaders = 0; - message->cpMsg = NULL; - message->cpHeaders = NULL; - message->cpBody = NULL; - return; -} - static lmtp_rc_t lmtp_cb_lhlo(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx) { /* @@ -568,36 +522,46 @@ static lmtp_rc_t lmtp_cb_mail(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx) { - lmtp_res_t res; - lmtp_rc_t rc = LMTP_OK; lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx; + lmtp_res_t res; 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."; lmtp_response(lmtp, &res); + return LMTP_OK; } - else if (ctx->message.mail_from != NULL) { + + if (ctx->msg != NULL) { res.statuscode = "503"; res.dsncode = "5.5.0"; res.statusmsg = "Sender already specified."; lmtp_response(lmtp, &res); + return LMTP_OK; + } + + if ((ctx->msg = msg_create()) == NULL) { + res.statuscode = "503"; // FIXME + res.dsncode = "5.5.0"; + res.statusmsg = "Internal error - memory."; + lmtp_response(lmtp, &res); + return LMTP_ERR_MEM; } - else - if (!str_parse(req->msg, "m/^MAIL From: <(.+@.+)>$/i", &ctx->message.mail_from)) { + + if (!str_parse(req->msg, "m/^MAIL From: <(.+@.+)>$/i", &ctx->msg->mail_from)) { res.statuscode = "553"; res.dsncode = "5.5.4"; res.statusmsg = "Domain name required for sender address."; lmtp_response(lmtp, &res); + return LMTP_OK; } - else { - res.statuscode = "250"; - res.dsncode = "2.1.0"; - res.statusmsg = "Sender ok."; - lmtp_response(lmtp, &res); - } - return rc; + + res.statuscode = "250"; + res.dsncode = "2.1.0"; + res.statusmsg = "Sender ok."; + lmtp_response(lmtp, &res); + return LMTP_OK; } static lmtp_rc_t lmtp_cb_rcpt(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *_ctx) @@ -607,7 +571,7 @@ char *cp; char *group; - if (ctx->message.mail_from == NULL) { + if (ctx->msg->mail_from == NULL) { res.statuscode = "503"; res.dsncode = "5.0.0"; res.statusmsg = "specify sender with MAIL first."; @@ -658,8 +622,8 @@ return LMTP_OK; } - fprintf(stderr, "DEBUG: cp=***%s***\n", cp); - argz_add(&ctx->message.azRcpt, &ctx->message.asRcpt, cp); + //fprintf(stderr, "DEBUG: cp=***%s***\n", cp); + argz_add(&ctx->msg->azRcpt, &ctx->msg->asRcpt, cp); argz_add(&ctx->azGroups, &ctx->asGroups, group); res.statuscode = "250"; res.dsncode = "2.1.5"; @@ -675,8 +639,9 @@ lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx; char errorstring[STDSTRLEN]; char *rcpt; + int i; - if (argz_count(ctx->message.azRcpt, ctx->message.asRcpt) == 0) { + if (argz_count(ctx->msg->azRcpt, ctx->msg->asRcpt) == 0) { res.statuscode = "503"; res.dsncode = "5.0.0"; res.statusmsg = "specify recipient with RCPT first."; @@ -689,11 +654,11 @@ res.statusmsg = "Enter mail, end with \".\" on a line by itself"; lmtp_response(lmtp, &res); - rc = lmtp_readmsg(lmtp, &ctx->message.cpMsg, MESSAGE_MAXLEN); + rc = lmtp_readmsg(lmtp, &ctx->msg->cpMsg, MESSAGE_MAXLEN); if (rc == LMTP_ERR_OVERFLOW) { rcpt = NULL; - while ((rcpt = argz_next(ctx->message.azRcpt, ctx->message.asRcpt, rcpt)) != NULL) { + while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) { res.statuscode = "500"; res.dsncode = "5.0.0"; res.statusmsg = "Overflow reading message"; //FIXME temp or perm error? @@ -704,7 +669,7 @@ if (rc == LMTP_ERR_SYSTEM) { rcpt = NULL; - while ((rcpt = argz_next(ctx->message.azRcpt, ctx->message.asRcpt, rcpt)) != NULL) { + while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) { res.statuscode = "500"; res.dsncode = "5.0.0"; str_format(errorstring, sizeof(errorstring), "System error reading message: %s", strerror(errno)); @@ -716,7 +681,7 @@ if(rc != LMTP_OK) { rcpt = NULL; - while ((rcpt = argz_next(ctx->message.azRcpt, ctx->message.asRcpt, rcpt)) != NULL) { + while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) { res.statuscode = "500"; res.dsncode = "5.0.0"; res.statusmsg = "Unknown error reading message"; //FIXME call lmtp_error()? @@ -725,14 +690,61 @@ } } - /* manipulate headers - * - remove To: and Cc: headers - * - (re)create Newsgroups: header - */ - prepareheader(ctx); +#if 0 + fprintf(stderr, "DEBUG: calling msg_split();\n"); + fprintf(stderr, "DEBUG: msg_split() returned %s\n", msg_error(ctx->msg, msg_split(ctx->msg))); +#endif + if (msg_split(ctx->msg) != MSG_OK) { + while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) { + res.statuscode = "500"; + res.dsncode = "5.0.0"; + res.statusmsg = "Error splitting message."; //FIXME call msg_error()? + lmtp_response(lmtp, &res); + return LMTP_OK; + } + } + +#if 0 + { //FIXME just a debug paragraph + char *cp; + cp = NULL; + while((cp = argz_next(ctx->azGroups, ctx->asGroups, cp)) != NULL) + fprintf(stderr, "DEBUG: lmtp Groups: ***%s***\n", cp); + } +#endif + ctx->msg->azNewsgroups = ctx->azGroups; + ctx->msg->asNewsgroups = ctx->asGroups; +#if 0 + { //FIXME just a debug paragraph + char *cp; + cp = NULL; + while((cp = argz_next(ctx->msg->azNewsgroups, ctx->msg->asNewsgroups, cp)) != NULL) + fprintf(stderr, "DEBUG: article Newsgroups: ***%s***\n", cp); + fprintf(stderr, "DEBUG: article Message-ID: ***%s***\n", ctx->msg->cpMsgid); + } +#endif + +#if 0 + fprintf(stderr, "DEBUG: calling msg_join();\n"); + fprintf(stderr, "DEBUG: msg_join() returned %s\n", msg_error(ctx->msg, msg_join(ctx->msg))); +#endif + if (msg_join(ctx->msg) != MSG_OK) { + while ((rcpt = argz_next(ctx->msg->azRcpt, ctx->msg->asRcpt, rcpt)) != NULL) { + res.statuscode = "500"; + res.dsncode = "5.0.0"; + res.statusmsg = "Error joining message."; //FIXME call msg_error()? + lmtp_response(lmtp, &res); + return LMTP_OK; + } + } + + 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); + } rcpt = NULL; - while ((rcpt = argz_next(ctx->message.azRcpt, ctx->message.asRcpt, 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); @@ -740,175 +752,10 @@ lmtp_response(lmtp, &res); } - resetmessage(&ctx->message); - return rc; -} - -lmtp_rc_t prepareheader(void *_ctx) -{ - lmtp2nntp_t *ctx = (lmtp2nntp_t *)_ctx; - char *cpName; - char *cpValue; - char *cpRem; - char *cp; - char *azNewsgroups; - int asNewsgroups; - char **aHeaders; - char *cpMsgid; - int i; - char *cpCut; - char *cpWrap; - - /**************** - * PARSE HEADER * FIXME make it nice - ****************/ - - if (!str_parse(ctx->message.cpMsg, "m/((?:.*?)\\n)\\n(.*)$/s", &ctx->message.cpHeaders, &ctx->message.cpBody)) - return LMTP_ERR_ARG; - - if (strlen(ctx->message.cpHeaders) < 4 + 1) - return LMTP_ERR_ARG; - memcpy(ctx->message.cpHeaders, "X-F:", 4); /* replace envelope From w/o colon by X-F: pseudotag */ - - // fprintf(stderr, "DEBUG: input ***%s***\n", ctx->message.cpHeaders); - while (str_parse(ctx->message.cpHeaders, "s/(.*?)\\n[ \\t]+(.*)/$1 $2/s", &cpRem)) { //FIXME poor man's s///g simulator - free(ctx->message.cpHeaders); - ctx->message.cpHeaders = cpRem; - } - /* - * FIXME str enhancement requests and bugs to be fixed - * - * - fix bug "not" [^...] working - * - improve str_parse(foo, "...", &foo) should free foo() on it's own - * - add "global" in s/search/replace/g - */ - // fprintf(stderr, "DEBUG: unwrapped ***%s***\n", ctx->message.cpHeaders); - - while (str_parse(ctx->message.cpHeaders, "m/^([\\w-]+?:)[ \\t]*(.*?)[ \\t]*\\n(.*)/s", &cpName, &cpValue, &cpRem)) { - free(ctx->message.cpHeaders); - ctx->message.cpHeaders = cpRem; - //fprintf(stderr, "DEBUG: raw Name(%s) = Value(%s)\n", cpName, cpValue); - argz_add(&ctx->message.azHeaders, &ctx->message.asHeaders, cpName); - argz_add(&ctx->message.azHeaders, &ctx->message.asHeaders, cpValue); - } - memcpy(ctx->message.azHeaders, "From", 4); /* replace envelope X-F: pseudotag with From w/o colon */ - // fprintf(stderr, "DEBUG: remainder ***%s***\n", ctx->message.cpHeaders); - // fprintf(stderr, "DEBUG: body ***%s***\n", ctx->message.cpBody); - - /********************* - * MANIPULATE HEADER * FIXME make it nice - *********************/ - - /* check for headers we care about and verfiy them, throw them away ... */ - cpMsgid = NULL; - cp = ctx->message.azHeaders; - while (cp != NULL) { - fprintf(stderr, "DEBUG: checking header ***%s***\n", cp); - if (strcasecmp("To:", cp) == 0) { - argz_delete(&ctx->message.azHeaders, &ctx->message.asHeaders, cp); /* name */ - argz_delete(&ctx->message.azHeaders, &ctx->message.asHeaders, cp); /* value */ - continue; - } //FIXME what bad things can happen here (odd number of argz, delete fails ... - if (strcasecmp("Cc:", cp) == 0) { - argz_delete(&ctx->message.azHeaders, &ctx->message.asHeaders, cp); /* name */ - argz_delete(&ctx->message.azHeaders, &ctx->message.asHeaders, cp); /* value */ - continue; - } //FIXME what bad things can happen here (odd number of argz, delete fails ... - if (strcasecmp("Message-ID:", cp) == 0) { - if ((cp = argz_next(ctx->message.azHeaders, ctx->message.asHeaders, cp)) == NULL) - break; - cpMsgid = cp; - if ((cp = argz_next(ctx->message.azHeaders, ctx->message.asHeaders, cp)) == NULL) - break; - continue; - } - if ((cp = argz_next(ctx->message.azHeaders, ctx->message.asHeaders, cp)) == NULL) - break; - if ((cp = argz_next(ctx->message.azHeaders, ctx->message.asHeaders, cp)) == NULL) - break; - } - if (cpMsgid == NULL) - exit(1); //FIXME - else - fprintf(stderr, "DEBUG: Message-ID = ***%s***\n", cpMsgid); - - /* create a proper Newsgroups: header */ - cp = NULL; - azNewsgroups = NULL; - asNewsgroups = 0; - while ((cp = argz_next(ctx->azGroups, ctx->asGroups, cp)) != NULL) { - // fprintf(stderr, "DEBUG: Group(%s)\n", cp); - argz_add(&azNewsgroups, &asNewsgroups, cp); - } - argz_stringify(azNewsgroups, asNewsgroups, ','); - argz_add(&ctx->message.azHeaders, &ctx->message.asHeaders, "Newsgroups:"); - argz_add(&ctx->message.azHeaders, &ctx->message.asHeaders, azNewsgroups); - - /* merge name/value pairs into single string */ - argz_add(&ctx->message.azHeaders, &ctx->message.asHeaders, ""); /* append empty string */ - if ((aHeaders = (char **)malloc((argz_count(ctx->message.azHeaders, - ctx->message.asHeaders) + 1) * sizeof(char *))) == NULL) - exit(1); //FIXME - argz_extract(ctx->message.azHeaders, ctx->message.asHeaders, aHeaders); - i=0; - while(1) { - if ((cp = aHeaders[++i]) == NULL) - break; - *(cp-1) = ' '; - if ((cp = aHeaders[++i]) == NULL) - break; - // *(cp-1) = '\n'; - } - - /* fold headers */ -//FIXME where to place this defines best -#define WRAPAT 120 -#define WRAPUSING "\n " - cp = NULL; - while ((cp = argz_next(ctx->message.azHeaders, ctx->message.asHeaders, cp)) != NULL) { - if (strlen(cp) >= WRAPAT) { - cpRem = cp; - cpWrap = NULL; - while (strlen(cpRem) >= WRAPAT) { - for (i = WRAPAT; i >= 1 && (cpRem[i] != ' ') && (cpRem[i] != '\t'); i--); - if (i == 0) - i = WRAPAT; /* sorry, hard cut at non-whitespace */ - if (i < WRAPAT) - i++; /* we don't care about the whitespace itself */ - cpCut = str_dup(cpRem, i); - //FIXME 1.) continue searching downwards skipping all whitespaces and 2.) as we know the length replace str_dup/ strcat/ free with strncat only - if (cpWrap == NULL) { - if ((cpWrap = (char *)malloc(strlen(cpCut)+strlen(WRAPUSING)+1)) == NULL) - exit(1); //FIXME - *cpWrap = '\0'; - } - else { - if ((cpWrap = (char *)realloc(cpWrap, strlen(cpWrap)+strlen(cpCut)+strlen(WRAPUSING)+1)) == NULL) - exit(1); //FIXME - strcat(cpWrap, WRAPUSING); - } - strcat(cpWrap, cpCut); - free(cpCut); - cpRem += i; - } - for (i = 0; i < strlen(cpRem) && ((cpRem[i] == ' ') || (cpRem[i] == '\t')); i++); - cpRem += i; - if (strlen(cpRem) > 0) { - if ((cpWrap = (char *)realloc(cpWrap, strlen(cpWrap)+strlen(cpRem)+strlen(WRAPUSING)+1)) == NULL) - exit(1); //FIXME - strcat(cpWrap, WRAPUSING); - strcat(cpWrap, cpRem); - } - argz_delete(&ctx->message.azHeaders, &ctx->message.asHeaders, cp); - argz_insert(&ctx->message.azHeaders, &ctx->message.asHeaders, cp, cpWrap); - free(cpWrap); - } - } + msg_destroy(ctx->msg); + ctx->msg = NULL; - argz_stringify(ctx->message.azHeaders, ctx->message.asHeaders, '\n'); - fprintf(stderr, "DEBUG: flat headers = ***%s***\n", ctx->message.azHeaders); - - return LMTP_OK; + return rc; } static lmtp_rc_t lmtp_cb_noop(lmtp_t *lmtp, lmtp_io_t *io, lmtp_req_t *req, void *ctx) @@ -929,7 +776,9 @@ lmtp_res_t res; lmtp_rc_t rc = LMTP_OK; - resetmessage(&ctx->message); + msg_destroy(ctx->msg); + ctx->msg = NULL; + res.statuscode = "250"; res.dsncode = "2.0.0"; res.statusmsg = "Reset state."; @@ -943,7 +792,9 @@ lmtp_res_t res; lmtp_rc_t rc = LMTP_EOF; - resetmessage(&ctx->message); + msg_destroy(ctx->msg); + ctx->msg = NULL; + resetsession(&ctx->session); res.statuscode = "221"; res.dsncode = "2.0.0"; Index: ossp-pkg/lmtp2nntp/msg.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/msg.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/msg.c,v' | diff -u /dev/null - -L'ossp-pkg/lmtp2nntp/msg.c' 2>/dev/null --- ossp-pkg/lmtp2nntp/msg.c +++ - 2024-04-25 01:57:17.123154125 +0200 @@ -0,0 +1,321 @@ + +#include +#include "msg.h" +#include "str.h" +#include "argz.h" +#include + +msg_t *msg_create(void) +{ + msg_t *msg; + + if ((msg = (msg_t *)malloc(sizeof(msg_t))) == NULL) + return NULL; + + msg->mail_from = NULL; + msg->azRcpt = NULL; + msg->asRcpt = 0; + msg->azNewsgroups = NULL; + msg->asNewsgroups = 0; + msg->azHeaders = NULL; + msg->asHeaders = 0; + msg->cpMsg = NULL; + msg->cpHeaders = NULL; + msg->cpBody = NULL; + msg->cpMsgid = NULL; + + return msg; +} + +void msg_destroy(msg_t *msg) +{ + if (msg == NULL) + return; + //FIXME what about non-graceful aborts? + if (msg->mail_from != NULL) + free(msg->mail_from); + if (msg->azRcpt != NULL) + free(msg->azRcpt); + if (msg->azHeaders != NULL) + free(msg->azHeaders); + if (msg->azNewsgroups != NULL) + free(msg->azNewsgroups); + if (msg->cpMsg != NULL) + free(msg->cpMsg); + if (msg->cpHeaders != NULL) + free(msg->cpHeaders); + if (msg->cpBody != NULL) + free(msg->cpBody); + free(msg); +} + +msg_rc_t msg_split(msg_t *msg) +{ + char *cpName; + char *cpValue; + char *cpRem; + char *cp; + + /* INPUTS + * + * msg->cpMsg + * must contain the wholly RFC822 formatted message with native + * (unescaped) dots at the beginning of a line, the 'From ' envelope, + * headers, double newline, body, '\0', no trailing dot; + * + * OUTPUTS + * + * msg->azHeaders, msg->asHeaders + * contains the headers in argz format, one logical '\0'-terminated line + * per header which might be wrapped into multiple '\n'-ended physical + * lines. The "To:" and "Cc:" headers are silently. The "Newsgroups:" and + * "Message-ID" headers are removed and their values are stored in + * separate structures (see below). + * + * msg->cpBody + * contains the unmodified body of the message, '\0'-terminated, no + * trailing dot. + * + * msg->cpMsgid + * contains the message id including surrounding angle brackets. + * + * msg->azNewsgroups, asNewsgroups + * is a argz-type array of strings containing the Newsgroups based on the + * header information. + */ + + /* split message into header and body */ + if (!str_parse(msg->cpMsg, "m/((?:.*?)\\n)\\n(.*)$/s", &msg->cpHeaders, &msg->cpBody)) + return MSG_ERR_SPLITSPLITBODY; + + /* replace envelope From w/o colon by X-F: pseudotag. This eliminates the + * special case of having one header, which is really an embedded + * envelope, not ending with a colon while all other do. After splitting + * headers into name and value pairs this action is reversed. + */ + if (strlen(msg->cpHeaders) < 4) + return MSG_ERR_SPLITLEN; + if (strncasecmp(msg->cpHeaders, "From", 4) != 0) + return MSG_ERR_SPLITMISSINGFROM; + memcpy(msg->cpHeaders, "X-F:", 4); + + /* unwrap header lines */ + //FIXME poor man's s///g simulator as current str library doesn't support //global substitution + while (str_parse(msg->cpHeaders, "s/(.*?)\\n[ \\t]+(.*)/$1 $2/s", &cpRem)) { + free(msg->cpHeaders); + msg->cpHeaders = cpRem; + } + + /* split header lines into names and values */ + //FIXME str enhancement requests and bugs to be fixed + //FIXME - fix bug "not" [^...] working + //FIXME - improve str_parse(foo, "...", &foo) should free foo() on it's own + //FIXME - add "global" in s/search/replace/g (see above "unwrap hader lines") + while (str_parse(msg->cpHeaders, "m/^([\\w-]+?:)[ \\t]*(.*?)[ \\t]*\\n(.*)/s", &cpName, &cpValue, &cpRem)) { + free(msg->cpHeaders); + msg->cpHeaders = cpRem; + argz_add(&msg->azHeaders, &msg->asHeaders, cpName); + argz_add(&msg->azHeaders, &msg->asHeaders, cpValue); + } + + /* reverse the 'From ' to 'X-F: ' replacement */ + memcpy(msg->azHeaders, "From", 4); /* replace envelope X-F: pseudotag with From w/o colon */ + + /* check for headers we care about and do whatever neccessary */ + msg->cpMsgid = NULL; + msg->azNewsgroups = NULL; + msg->asNewsgroups = 0; + cp = msg->azHeaders; + while (cp != NULL) { + if (strcasecmp("To:", cp) == 0) { + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */ + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */ + continue; + } + if (strcasecmp("Cc:", cp) == 0) { + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */ + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */ + continue; + } + if (strcasecmp("Message-ID:", cp) == 0) { + if (msg->cpMsgid != NULL) + return MSG_ERR_SPLITIDMULTI; + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */ + //fprintf(stderr, "DEBUG: Message-ID cp = ***%s***\n", cp); + if ((cp == NULL) || (strlen(cp) == 0)) /* get value */ + return MSG_ERR_SPLITIDEMPTY; + if ((msg->cpMsgid = strdup(cp)) == NULL) + return MSG_ERR_MEM; + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */ + continue; + } + if (strcasecmp("Newsgroups:", cp) == 0) { + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del name */ + //fprintf(stderr, "DEBUG: Newsgroups cp = ***%s***\n", cp); + if (argz_add(&msg->azNewsgroups, &msg->asNewsgroups, cp) != 0) /* get value */ + return MSG_ERR_MEM; + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); /* del value */ + continue; + } + if ((cp = argz_next(msg->azHeaders, msg->asHeaders, cp)) == NULL) /* next value */ + break; + if ((cp = argz_next(msg->azHeaders, msg->asHeaders, cp)) == NULL) /* next name */ + break; + } + if (msg->cpMsgid == NULL) + return MSG_ERR_SPLITIDNONE; + + if (msg->azNewsgroups != NULL) { + argz_stringify(msg->azNewsgroups, msg->asNewsgroups, ','); + if (argz_create_sep(msg->azNewsgroups, ',', &msg->azNewsgroups, &msg->asNewsgroups) != 0) + return MSG_ERR_MEM; + } + + return MSG_OK; +} + +msg_rc_t msg_join(msg_t *msg) +{ + char *cp; + char *cpRem; + char **aHeaders; + int i; + char *cpCut; + char *cpWrap; + char *cpNew; + + /* verify asNewsgroups */ + if (msg->azNewsgroups == NULL) + return MSG_ERR_JOINGROUPNONE; + argz_stringify(msg->azNewsgroups, msg->asNewsgroups, ','); + //fprintf(stderr, "DEBUG: join consolidated azNewsgroups = ***%s***\n", msg->azNewsgroups); + if (strlen(msg->azNewsgroups) == 0) + return MSG_ERR_JOINGROUPEMPTY; + argz_add(&msg->azHeaders, &msg->asHeaders, "Newsgroups:"); + argz_add(&msg->azHeaders, &msg->asHeaders, msg->azNewsgroups); + + /* verify Message-ID */ + if (msg->cpMsgid == NULL) + return MSG_ERR_JOINIDNONE; + if (strlen(msg->cpMsgid) == 0) + return MSG_ERR_JOINIDEMPTY; + argz_add(&msg->azHeaders, &msg->asHeaders, "Message-ID:"); + argz_add(&msg->azHeaders, &msg->asHeaders, msg->cpMsgid); + + /* merge name/value pairs into single string */ + argz_add(&msg->azHeaders, &msg->asHeaders, ""); /* append empty string */ + if ((aHeaders = (char **)malloc((argz_count(msg->azHeaders, + msg->asHeaders) + 1) * sizeof(char *))) == NULL) + exit(1); //FIXME + argz_extract(msg->azHeaders, msg->asHeaders, aHeaders); + i=0; + while(1) { + if ((cp = aHeaders[++i]) == NULL) + break; + *(cp-1) = ' '; + if ((cp = aHeaders[++i]) == NULL) + break; + // *(cp-1) = '\n'; + } + + /* fold headers */ +//FIXME where to place this defines best +#define WRAPAT 120 +#define WRAPUSING "\n " + cp = NULL; + while ((cp = argz_next(msg->azHeaders, msg->asHeaders, cp)) != NULL) { + if (strlen(cp) >= WRAPAT) { + cpRem = cp; + cpWrap = NULL; + while (strlen(cpRem) >= WRAPAT) { + for (i = WRAPAT; i >= 1 && (cpRem[i] != ' ') && (cpRem[i] != '\t'); i--); + if (i == 0) + i = WRAPAT; /* sorry, hard cut at non-whitespace */ + if (i < WRAPAT) + i++; /* we don't care about the whitespace itself */ + cpCut = str_dup(cpRem, i); + //FIXME 1.) continue searching downwards skipping all whitespaces and 2.) as we know the length replace str_dup/ strcat/ free with strncat only + if (cpWrap == NULL) { + if ((cpWrap = (char *)malloc(strlen(cpCut)+strlen(WRAPUSING)+1)) == NULL) + exit(1); //FIXME + *cpWrap = '\0'; + } + else { + if ((cpWrap = (char *)realloc(cpWrap, strlen(cpWrap)+strlen(cpCut)+strlen(WRAPUSING)+1)) == NULL) + exit(1); //FIXME + strcat(cpWrap, WRAPUSING); + } + strcat(cpWrap, cpCut); + free(cpCut); + cpRem += i; + } + for (i = 0; i < strlen(cpRem) && ((cpRem[i] == ' ') || (cpRem[i] == '\t')); i++); + cpRem += i; + if (strlen(cpRem) > 0) { + if ((cpWrap = (char *)realloc(cpWrap, strlen(cpWrap)+strlen(cpRem)+strlen(WRAPUSING)+1)) == NULL) + exit(1); //FIXME + strcat(cpWrap, WRAPUSING); + strcat(cpWrap, cpRem); + } + argz_delete(&msg->azHeaders, &msg->asHeaders, cp); + argz_insert(&msg->azHeaders, &msg->asHeaders, cp, cpWrap); + free(cpWrap); + } + } + + argz_stringify(msg->azHeaders, msg->asHeaders, '\n'); + msg->cpHeaders = msg->azHeaders; + + if (argz_create_sep(msg->cpBody, '\n', &msg->azBody, &msg->asBody) != 0) + return MSG_ERR_MEM; + + /* escape dots at the beginning of each line */ + cp = NULL; + while ((cp =argz_next(msg->azBody, msg->asBody, cp)) != NULL) { + if (*cp == '.') { + if ((cpNew = malloc(strlen(cp) + 1)) == NULL) + return MSG_ERR_MEM; + *cpNew = '.'; + cpNew++; + *cpNew = '\0'; + strcat(cpNew, cp); + argz_delete(&msg->azBody, &msg->asBody, cp); + argz_insert(&msg->azBody, &msg->asBody, cp, cpNew); + } + } + + 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) + 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 */ + + //fprintf(stderr, "DEBUG: Message = ***%s***\n", msg->cpMsg); + + return MSG_OK; +} + +char *msg_error(msg_t *msg, msg_rc_t rc) +{ + char *str; + str = "MSG: no description"; + if (rc == MSG_OK ) str = "MSG: no error"; + else if (rc == MSG_ERR_MEM ) str = "MSG: memory"; + else if (rc == MSG_ERR_SPLITSPLITBODY ) str = "MSG: split into header and body failed"; + else if (rc == MSG_ERR_SPLITLEN ) str = "MSG: header is too short"; + else if (rc == MSG_ERR_SPLITMISSINGFROM ) str = "MSG: header is missing 'From ' envelope"; + else if (rc == MSG_ERR_SPLITIDNONE ) str = "MSG: header is missing 'Message-ID'"; + else if (rc == MSG_ERR_SPLITIDEMPTY ) str = "MSG: header has empty 'Message-ID'"; + else if (rc == MSG_ERR_SPLITIDMULTI ) str = "MSG: header has multiple 'Message-ID's"; + else if (rc == MSG_ERR_JOINGROUPNONE ) str = "MSG: join with no 'Newsgroup'"; + else if (rc == MSG_ERR_JOINGROUPEMPTY ) str = "MSG: join with empty 'Newsgroup'"; + else if (rc == MSG_ERR_JOINIDNONE ) str = "MSG: join with no 'Message-ID'"; + else if (rc == MSG_ERR_JOINIDEMPTY ) str = "MSG: join with empty 'Message-ID'"; + return str; +} + Index: ossp-pkg/lmtp2nntp/msg.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/msg.h,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/msg.h,v' | diff -u /dev/null - -L'ossp-pkg/lmtp2nntp/msg.h' 2>/dev/null --- ossp-pkg/lmtp2nntp/msg.h +++ - 2024-04-25 01:57:17.126173171 +0200 @@ -0,0 +1,46 @@ + +#ifndef __MSG_H__ +#define __MSG_H__ + +#include + +typedef struct { + char *cpMsg; /* the wholly message to be received by DATA command */ + char *cpHeaders; /* header part of message above */ + char *cpBody; /* body part of message above */ + char *cpMsgid; + char *mail_from; + char *azRcpt; + size_t asRcpt; + char *azHeaders; + size_t asHeaders; + char *azBody; + size_t asBody; + char *azNewsgroups; + size_t asNewsgroups; +} msg_t; + +typedef enum { + MSG_OK, + MSG_ERR_MEM, + MSG_ERR_SPLITSPLITBODY, + MSG_ERR_SPLITLEN, + MSG_ERR_SPLITMISSINGFROM, + MSG_ERR_SPLITIDNONE, + MSG_ERR_SPLITIDEMPTY, + MSG_ERR_SPLITIDMULTI, + MSG_ERR_JOINGROUPNONE, + MSG_ERR_JOINGROUPEMPTY, + MSG_ERR_JOINIDNONE, + MSG_ERR_JOINIDEMPTY, + MSG_ERR_ARG +} msg_rc_t; + +msg_t *msg_create(void); +msg_rc_t msg_split(msg_t *); +msg_rc_t msg_join(msg_t *); +void msg_destroy(msg_t *); +char *msg_error(msg_t *, msg_rc_t); + +#endif /* __MSG_H__ */ + Index: ossp-pkg/lmtp2nntp/nntp.c RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.c,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.c,v' 2>/dev/null --- nntp.c 2001/08/07 09:05:55 1.3 +++ nntp.c 2001/08/13 06:41:42 1.4 @@ -182,6 +182,7 @@ buf[n] = '\0'; /* string termination */ if (n == (buflen-1)) return NNTP_ERR_OVERFLOW; + fprintf(stderr, "DEBUG: nntp_readline >>>%s\n", buf); return NNTP_OK; } @@ -193,73 +194,94 @@ return NNTP_ERR_ARG; strncpy(tmp, buf, NNTP_LINE_MAXLEN-3); strcat(tmp, "\r\n"); + fprintf(stderr, "DEBUG: nntp_writeline >>>%s", tmp); if (nntp->io.write(nntp->wfd, tmp, strlen(tmp)) < 0) return NNTP_ERR_SYSTEM; return NNTP_OK; } -nntp_rc_t nntp_post(nntp_t *nntp, char *msg) +nntp_rc_t nntp_post(nntp_t *nntp, msg_t *msg) { nntp_rc_t rc = NNTP_OK; char line[NNTP_LINE_MAXLEN]; - if ((rc = nntp_readline(nntp, line, sizeof(line))) != NNTP_OK) - return rc; - fprintf(stderr, "READ:<%s>\n", line); - if ((rc = nntp_writeline(nntp, "mode reader")) != NNTP_OK) + /* check if this server already knows that artice + * > STAT + * < 223 yes, article already known + * < 430 no, i don't know the article, yet + */ + *line = '\0'; + strcat(line, "STAT "); + strcat(line, msg->cpMsgid); + if ((rc = nntp_writeline(nntp, line)) != NNTP_OK) return rc; - fprintf(stderr, "WRITE:\n"); if ((rc = nntp_readline(nntp, line, sizeof(line))) != NNTP_OK) return rc; - fprintf(stderr, "READ:<%s>\n", line); - if ((rc = nntp_writeline(nntp, "quit")) != NNTP_OK) + if (strncmp(line, "223", 3) == 0) + return NNTP_OK; + if (strncmp(line, "430", 3) != 0) + return NNTP_ERR_POSTPERM; //FIXME + + /* post the article + * > POST + * < 340 gimme that thing + * > From: ... + * > Subject: ... + * > Newsgroups: ... + * > Message-ID: <...> + * > [additional headers] + * > + * > [body with dots escaped] + * > . + * < 240 ok, thank you + * < 441 duplicate (ok for us) + */ + *line = '\0'; + strcat(line, "POST "); + strcat(line, msg->cpMsgid); + if ((rc = nntp_writeline(nntp, line)) != NNTP_OK) return rc; - fprintf(stderr, "WRITE:\n"); if ((rc = nntp_readline(nntp, line, sizeof(line))) != NNTP_OK) return rc; - fprintf(stderr, "READ:<%s>\n", line); + if (strncmp(line, "xxx", 3) == 0) + return NNTP_OK; + if (strncmp(line, "340", 3) != 0) + return NNTP_ERR_POSTPERM; //FIXME + +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) + 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; + fprintf(stderr, "DEBUG: answer to post = ***%s***, rc = %s\n", line, nntp_error(nntp, rc)); + }; + } + return NNTP_OK; -#if 0 //FIXME - allservers = x; /* total number of servers specified */ - deliveries = 0; /* counts successful deliveries */ - for (i=0; i < allservers; i++) { - if (post() == NNTP_OK) { +#if 0 /* check if this server accepts at least one of the newsgroups > GROUP < 211 yes, group exists < 411 no, group doesn't exist */ - /* check if this server already knows that artice - > STAT - < 223 yes, article already known - < 430 no, i don't know the article, yet - */ - - /* post the article - > POST - < 340 gimme that thing - > From: ... - > Subject: ... - > Newsgroups: ... - > Message-ID: <...> - > [additional headers] - > - > [body with dots escaped] - > . - < 240 ok, thank you - < 441 duplicate (ok for us) - */ - } - } - if (((mode == DELIVERYMODE_MANY) || (mode == DELIVERYMODE_ONCE)) && (deliveries >= 1)) - rc = NNTP_OK; - else if ((mode == DELIVERYMODE_ALL) && (deliveries == allservers)) - rc = NNTP_OK - else - rc = NNTP_ERR_POST; #endif - return rc; } char *nntp_error(nntp_t *nntp, nntp_rc_t rc) Index: ossp-pkg/lmtp2nntp/nntp.h RCS File: /v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.h,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/lmtp2nntp/Attic/nntp.h,v' 2>/dev/null --- nntp.h 2001/08/07 09:05:56 1.2 +++ nntp.h 2001/08/13 06:41:42 1.3 @@ -34,6 +34,7 @@ #include #include #include +#include "msg.h" struct nntp_st; typedef struct nntp_st nntp_t; @@ -51,6 +52,8 @@ NNTP_ERR_SYSTEM, NNTP_ERR_ARG, NNTP_ERR_OVERFLOW, + NNTP_ERR_POSTPERM, + NNTP_ERR_POSTDEFER, NNTP_ERR_INIT } nntp_rc_t; @@ -60,7 +63,7 @@ void nntp_destroy (nntp_t *); nntp_rc_t nntp_readline (nntp_t *, char *, size_t); nntp_rc_t nntp_writeline(nntp_t *, char *); -nntp_rc_t nntp_post (nntp_t *, char *); +nntp_rc_t nntp_post (nntp_t *, msg_t *msg); char *nntp_error (nntp_t *, nntp_rc_t); #endif /* __NNTP_H__ */