#include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_LIMITS_H #include #endif #ifdef PERL_EMBED #include #include #ifdef OLD_PERL #ifndef ERRSV # define ERRSV (GvSV(errgv)) /* needed for perl 5.004 and earlier */ #endif #ifndef PL_na # define PL_na (na) #endif #endif /* OLD_PERL */u #endif #ifdef HAVE_DIRENT_H # include #else # define dirent direct # ifdef HAVE_SYS_NDIR_H # include # endif # ifdef HAVE_SYS_DIR_H # include # endif #endif #include "suck_config.h" #include "both.h" #include "phrases.h" struct nntp_auth { char *userid; char *passwd; int autoauth; int use_env; }; typedef struct { char *batch; char *prefix; char *host; char *filter_args[RPOST_MAXARGS]; int filter_argc; int filter_infilenr; /* nr of arg that we replace with infile */ char *filter_outfile; /* pointer to name of outfile */ int deleteyn; int do_modereader; int debug; struct nntp_auth auth; FILE *status_fptr; unsigned short int portnr; const char *phrases; char *rnews_file; char *rnews_path; int sockfd; int show_name; int ignore_readonly; int do_ssl; void *ssl_struct; #ifdef PERL_EMBED PerlInterpreter *perl_int; #endif } Args, *Pargs; /* function declarations */ int do_article(Pargs, FILE *); int do_batch(Pargs); int do_rnews(Pargs); char *do_filter(Pargs, char *); int send_command(Pargs, const char *, char **, int); int do_authenticate(Pargs); int scan_args(Pargs, int, char *[]); int filter_post_article(Pargs, char *); void log_fail(char *, char *); void load_phrases(Pargs); void free_phrases(void); int parse_filter_args(Pargs myargs, int, char **); #ifdef PERL_EMBED void parse_perl(Pargs, char *); void perl_done(Pargs); char *filter_perl(Pargs, char *); #endif #define RNEWS_START "#! rnews" /* string that denotes the begin of a new message in rnews file */ #define RNEWS_START_LEN 8 #define TEMP_ARTICLE "tmp-article" /* name for temp article in rnews_path */ /* stuff needed for language phrases */ /* set up defaults */ char **rpost_phrases = default_rpost_phrases; char **both_phrases = default_both_phrases; enum { RETVAL_ERROR = -1, RETVAL_OK, RETVAL_ARTICLE_PROB, RETVAL_NOAUTH, RETVAL_UNEXPECTEDANS}; /*------------------------------------------------*/ int main(int argc, char *argv[], char *env[]) { char *inbuf; int response, retval, loop, fargc, i; struct hostent *hi; struct stat sbuf; char **args, **fargs; Args myargs; /* initialize everything */ retval = RETVAL_OK; fargc = 0; fargs = NULL; myargs.batch = NULL; myargs.prefix =NULL; myargs.status_fptr = stdout; myargs.deleteyn = FALSE; myargs.auth.userid = NULL; myargs.auth.passwd = NULL; myargs.auth.autoauth = FALSE; myargs.auth.use_env = FALSE; myargs.do_modereader = FALSE; myargs.portnr = DEFAULT_NNRP_PORT; myargs.host = getenv("NNTPSERVER"); /* the default */ myargs.phrases = NULL; myargs.debug = FALSE; myargs.rnews_file = NULL; myargs.rnews_path = NULL; myargs.filter_argc = 0; myargs.filter_infilenr = -1; myargs.filter_outfile = NULL; myargs.show_name = FALSE; myargs.ignore_readonly = FALSE; myargs.do_ssl = FALSE; myargs.ssl_struct = NULL; #ifdef PERL_EMBED myargs.perl_int = NULL; #endif /* have to do this next so if set on cmd line, overrides this */ #ifdef N_PHRASES /* in case someone nukes def */ if(stat(N_PHRASES, &sbuf) == 0 && S_ISREG(sbuf.st_mode)) { /* we have a regular phrases file make it the default */ myargs.phrases = N_PHRASES; } #endif /* allow no args, only the hostname, or hostname as first arg */ /* also have to do the file argument checking */ switch(argc) { case 1: break; case 2: /* the fargs == NULL test so only process first file name */ if(argv[1][0] == FILE_CHAR) { if((fargs = build_args(&argv[1][1], &fargc)) != NULL) { retval = scan_args(&myargs, fargc, fargs); } } else { myargs.host = argv[1]; } break; default: for(loop=1;looph_name, NULL); if(myargs.debug == TRUE) { do_debug("Sending quit"); } send_command(&myargs, "quit\r\n", NULL, 0); disconnect_from_nntphost(myargs.sockfd, myargs.do_ssl, &myargs.ssl_struct); } } #ifdef PERL_EMBED if(myargs.perl_int != NULL) { perl_done(&myargs); } #endif if(myargs.status_fptr != NULL && myargs.status_fptr != stdout) { fclose(myargs.status_fptr); } free_phrases(); /* do this last so everything is displayed correctly */ exit(retval); } /*----------------------------------------------------------------------------------*/ int do_article(Pargs myargs, FILE *fptr) { int len, response, retval, longline, dupeyn, i; char buf[MAXLINLEN+4], *inbuf, *ptr = NULL; /* the +4 in NL, CR, if have to double . in first pos */ retval = RETVAL_OK; longline = FALSE; /* Initiate post mode don't use IHAVE since I'd have to scan the message for the msgid, */ /* then rewind and reread the file The problem lies in if I'm using STDIN for the message, */ /* I can't rewind!!!!, so no IHAVE */ response = send_command(myargs, "POST\r\n", &inbuf, 340); fputs(inbuf, myargs->status_fptr); if(response!=RETVAL_OK) { error_log(ERRLOG_REPORT, rpost_phrases[5], NULL); retval = RETVAL_ERROR; } else { while(fgets(buf, MAXLINLEN, fptr) != NULL) { len=strlen(buf); if(longline == FALSE) { /* only check this if we are at the beginning of a line */ if(buf[0]=='.') { /* Yup, this has to be doubled */ memmove(buf+1,buf,++len); buf[0]='.'; } } if(buf[len-1] == '\n') { /* only do this if we have an EOL in buffer */ if(buf[len-2] != '\r') { /* only add the \r\n if it's not already there. */ strncpy(&buf[len-1],"\r\n",3); } longline = FALSE; } else { longline = TRUE; } sputline(myargs->sockfd, buf, myargs->do_ssl, myargs->ssl_struct); if(myargs->debug == TRUE) { do_debug("ARTICLE: %s", buf); } } /* if the last line didn't have a nl on it, we need to */ /* put one so that the eom is recognized */ if(longline == TRUE) { sputline(myargs->sockfd, "\r\n", myargs->do_ssl, myargs->ssl_struct); } sputline(myargs->sockfd, ".\r\n", myargs->do_ssl, myargs->ssl_struct); if(myargs->debug == TRUE) { do_debug("ARTICLE END\n"); } if((i = sgetline(myargs->sockfd, &inbuf, myargs->do_ssl, myargs->ssl_struct)) < 0) { retval = RETVAL_ERROR; } else { fputs(inbuf, myargs->status_fptr); if(myargs->debug == TRUE) { do_debug("RESPONSE: %s", inbuf); } ptr = number(inbuf, &response); } if(retval == RETVAL_OK && response!=240) { dupeyn = FALSE; if(response == 441) { number(ptr, &response); } if(response == 435) { dupeyn = TRUE; } else { /* M$ server sends "441 (615) Article Rejected -- Duplicate Message ID" handle that */ /* can't just call nr, cause of parens */ /* ptr should be at ( after 441 */ if( *ptr == '(' ) { number(++ptr, &response); if(response == 615) { dupeyn = TRUE; } } else if (strstr(inbuf, RPOST_DUPE_STR) != NULL || strstr(inbuf, RPOST_DUPE_STR2)) { dupeyn = TRUE; } } if(dupeyn == TRUE) { print_phrases(myargs->status_fptr, rpost_phrases[6], NULL); } else { error_log(ERRLOG_REPORT, rpost_phrases[7], inbuf, NULL); retval = RETVAL_ARTICLE_PROB; } } } return retval; } /*----------------------------------------------------------------*/ int send_command(Pargs myargs, const char *cmd, char **ret_response, int good_response) { /* this is needed so can do user authorization */ int len, retval = RETVAL_OK, nr; char *resp; if(myargs->debug == TRUE) { do_debug("sending command: %s", cmd); } sputline(myargs->sockfd, cmd, myargs->do_ssl, myargs->ssl_struct); len = sgetline(myargs->sockfd, &resp, myargs->do_ssl, myargs->ssl_struct); if( len < 0) { retval = RETVAL_ERROR; } else { if(myargs->debug == TRUE) { do_debug("got answer: %s", resp); } number(resp, &nr); if(nr == 480 ) { /* we must do authorization */ retval = do_authenticate(myargs); if(retval == RETVAL_OK) { /* resend command */ sputline(myargs->sockfd, cmd, myargs->do_ssl, myargs->ssl_struct); if(myargs->debug == TRUE) { do_debug("sending command: %s", cmd); } len = sgetline(myargs->sockfd, &resp, myargs->do_ssl, myargs->ssl_struct); if( len < 0) { retval = RETVAL_ERROR; } else { number(resp,&nr); if(myargs->debug == TRUE) { do_debug("got answer: %s", resp); } } } } if (good_response != 0 && nr != good_response) { error_log(ERRLOG_REPORT, rpost_phrases[18],cmd,resp,NULL); retval = RETVAL_UNEXPECTEDANS; } } if(ret_response != NULL) { *ret_response = resp; } return retval; } /*----------------------------------*/ /* authenticate when receive a 480 */ /*----------------------------------*/ int do_authenticate(Pargs myargs) { int len, nr, retval = RETVAL_OK; char *resp, buf[MAXLINLEN]; /* we must do authorization */ if((myargs->auth).userid == NULL || (myargs->auth).passwd == NULL) { error_log(ERRLOG_REPORT, rpost_phrases[43], NULL); retval = RETVAL_NOAUTH; } else { print_phrases(myargs->status_fptr, rpost_phrases[41], NULL); sprintf(buf, "AUTHINFO USER %s\r\n", (myargs->auth).userid); if(myargs->debug == TRUE) { do_debug("sending command: %s", buf); } sputline(myargs->sockfd, buf, myargs->do_ssl, myargs->ssl_struct); len = sgetline(myargs->sockfd, &resp, myargs->do_ssl, myargs->ssl_struct); if( len < 0) { retval = RETVAL_ERROR; } else { if(myargs->debug == TRUE) { do_debug("got answer: %s", resp); } number(resp, &nr); if(nr == 480) { /* this is because of the pipelining code */ /* we get the second need auth */ /* just ignore it and get the next line */ /* which should be the 381 we need */ if((len = sgetline(myargs->sockfd, &resp, myargs->do_ssl, myargs->ssl_struct)) < 0) { retval = RETVAL_ERROR; } else { number(resp, &nr); } } if(retval == RETVAL_OK) { if(nr != 381) { error_log(ERRLOG_REPORT, rpost_phrases[16], resp, NULL); retval = RETVAL_NOAUTH; } else { sprintf(buf, "AUTHINFO PASS %s\r\n", (myargs->auth).passwd); sputline(myargs->sockfd, buf, myargs->do_ssl, myargs->ssl_struct); if(myargs->debug == TRUE) { do_debug("sending command: %s", buf); } len = sgetline(myargs->sockfd, &resp, myargs->do_ssl, myargs->ssl_struct); if(len < 0) { retval = RETVAL_ERROR; } else { if(myargs->debug == TRUE) { do_debug("got answer: %s", resp); } number(resp, &nr); switch(nr) { case 281: /* bingo */ retval = RETVAL_OK; print_phrases(myargs->status_fptr, rpost_phrases[42], NULL); break; case 502: /* permission denied */ retval = RETVAL_NOAUTH; error_log(ERRLOG_REPORT, rpost_phrases[17], NULL); break; default: /* wacko error */ error_log(ERRLOG_REPORT, rpost_phrases[16], resp, NULL); retval = RETVAL_NOAUTH; break; } } } } } } return retval; } /*--------------------------------------------------------------------------------------*/ int scan_args(Pargs myargs, int argc, char *argv[]) { int loop, retval = RETVAL_OK; for(loop=0;loopdebug == TRUE) { do_debug("Checking arg #%d-%d: '%s'\n", loop, argc, argv[loop]); } /* check for valid args format */ if(argv[loop][0] != '-' && argv[loop][0] != FILE_CHAR) { retval = RETVAL_ERROR; } if(argv[loop][0] == '-' && argv[loop][2] != '\0') { retval = RETVAL_ERROR; } if(retval != RETVAL_OK) { error_log(ERRLOG_REPORT, rpost_phrases[19], argv[loop], NULL); } else if(argv[loop][0] != FILE_CHAR) { switch(argv[loop][1]) { case 'h': /* hostname */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[20], NULL); retval = RETVAL_ERROR; } else { myargs->host = argv[++loop]; } break; case 'b': /* batch file Mode, next arg = batch file */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[21], NULL); retval = RETVAL_ERROR; } else { myargs->batch = argv[++loop]; } break; case 'p': /* specify directory prefix for files in batch file */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[22], NULL); retval = RETVAL_ERROR; } else { myargs->prefix = argv[++loop]; } break; case 'f': /* filter prg, rest of cmd line is args */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[23], NULL); retval = RETVAL_ERROR; } else { /* set up filter args send it first arg to filter and arg count */ retval = parse_filter_args(myargs, argc - (loop+1), &(argv[loop+1])); loop = argc; /* terminate main loop */ } break; #ifdef PERL_EMBED case 'F': /* filter using embedded perl */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[33], NULL); } else { /* parse the perl filter */ parse_perl(myargs, argv[++loop]); } break; #endif case 'e': /* use default error log path */ error_log(ERRLOG_SET_FILE, ERROR_LOG,NULL); break; case 'E': /* error log path */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, "%s\n",rpost_phrases[24],NULL); retval = RETVAL_ERROR; } else { error_log(ERRLOG_SET_FILE, argv[++loop], NULL); } break; case 's': /* use default status log path */ if((myargs->status_fptr = fopen(STATUS_LOG, "a")) == NULL) { MyPerror(rpost_phrases[25]); retval = RETVAL_ERROR; } break; case 'S': /* status log path */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[26],NULL); retval = RETVAL_ERROR; } else if((myargs->status_fptr = fopen(argv[++loop], "a")) == NULL) { MyPerror(rpost_phrases[25]); retval = RETVAL_ERROR; } break; case 'd': /* delete batch file on success */ myargs->deleteyn = TRUE; break; case 'u': /* do auto-authenticate */ myargs->auth.autoauth = TRUE; break; case 'U': /* next arg is userid for authorization */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[27],NULL); retval = RETVAL_ERROR; } else { myargs->auth.userid = argv[++loop]; } break; case 'P': /* next arg is password for authorization */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[28],NULL); retval = RETVAL_ERROR; } else { myargs->auth.passwd = argv[++loop]; } break; case 'Q': /* get userid/passwd from env */ myargs->auth.use_env = TRUE; myargs->auth.passwd = getenv("NNTP_PASS"); myargs->auth.userid = getenv("NNTP_USER"); break; case 'M': /* do mode reader command */ myargs->do_modereader = TRUE; break; case 'N': /* override port number */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[29],NULL); retval = RETVAL_ERROR; } else { myargs->portnr = atoi(argv[++loop]); } break; case 'l': /* language phrase file */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[31],NULL); retval = RETVAL_ERROR; } else { myargs->phrases = argv[++loop]; } break; case 'D': /* debug */ myargs->debug = TRUE; /* so error_log goes to debug too */ error_log(ERRLOG_SET_DEBUG, NULL, NULL); break; case 'r': /* do rnews next args base name then path for the rnews files */ if(loop+2 >= argc) { error_log(ERRLOG_REPORT, rpost_phrases[38], NULL); retval = RETVAL_ERROR; } else { myargs->rnews_file = argv[++loop]; myargs->rnews_path = argv[++loop]; } break; case 'n': /* show the file name as we're uploading it */ myargs->show_name = TRUE; break; case 'i': /* ignore read_only opening announcement */ myargs->ignore_readonly = TRUE; break; #ifdef TIMEOUT case 'T': /* timeout */ if(loop+1 == argc) { error_log(ERRLOG_REPORT, rpost_phrases[31], NULL); retval = RETVAL_ERROR; } else { TimeOut = atoi(argv[++loop]); } break; #endif #ifdef HAVE_LIBSSL case 'z': /* use SSL */ myargs->do_ssl = TRUE; myargs->portnr = DEFAULT_SSL_PORT; break; #endif default: error_log(ERRLOG_REPORT, rpost_phrases[30], argv[loop],NULL); break; } } } return retval; } #ifdef PERL_EMBED /*-----------------------------------------------------------------------------------------*/ void parse_perl(Pargs args, char *fname) { /* this code is copied from killprg.c killperl_setup() */ /* which comes from PERLEMBED man page */ char *ptr = NULL; char *prgs[] = { ptr, ptr }; if ((args->perl_int = perl_alloc()) == NULL) { error_log(ERRLOG_REPORT, rpost_phrases[34], NULL); } else { if(args->debug == TRUE) { do_debug("Perl program name =%s\n", fname); } perl_construct(args->perl_int); prgs[1] = fname; if(perl_parse(args->perl_int, NULL, 2, prgs, NULL) == 0) { perl_run(args->perl_int); } else { error_log(ERRLOG_REPORT, rpost_phrases[35], fname, NULL); perl_done(args); } } } /*---------------------------------------------------------------------------------------*/ void perl_done(Pargs args) { /* all done, free everything up */ if(args->perl_int != NULL) { perl_destruct(args->perl_int); perl_free(args->perl_int); args->perl_int = NULL; } } /*--------------------------------------------------------------------------------------*/ char *filter_perl(Pargs myargs, char *file) { int i; char *args[2] ={ NULL, NULL}; char infilen[MAXLINLEN+1]; char *infile=NULL; dSP; /* perl stack pointer */ SV *fname; /* used to get fname off of perl stack */ /* here's where we send it to perl and get back our filename */ /* we need infile to become our file name to post*/ /* this code comes from chk_msg_kill_perl() which uses */ /* both perlcall and perlembed man pages */ /* set up args */ args[0] = file; if(myargs->debug == TRUE) { do_debug("Calling %s with arg %s\n", PERL_RPOST_SUB, file); } ENTER; SAVETMPS; PUSHMARK(SP); i = perl_call_argv(PERL_RPOST_SUB, G_SCALAR | G_EVAL | G_KEEPERR, args); SPAGAIN; if(SvTRUE(ERRSV)) { error_log(ERRLOG_REPORT, rpost_phrases[36], SvPV(ERRSV,PL_na)); POPs; perl_done(myargs); } else if(i != 1) { error_log(ERRLOG_REPORT, rpost_phrases[37], PERL_RPOST_SUB, NULL); perl_done(myargs); } else { fname = POPs; infile = SvPV(fname, PL_na); if(myargs->debug == TRUE) { do_debug("got string =%s\n", null_str(infile)); } /* have to do the following cause as soon as we do FREETMPS, the */ /* data that infile points to will disappear */ strcpy(infilen, infile); infile = infilen; /* so we return the name of the file */ } PUTBACK; FREETMPS; LEAVE; return infile; } #endif /*---------------------------------------------------------------------------------------*/ int parse_filter_args(Pargs myargs, int argcount, char **args) { int argon, loop, i, retval = RETVAL_OK; /* build filter args */ i = strlen(RPOST_FILTER_OUT); /* just in case */ myargs->filter_outfile = NULL; myargs->filter_infilenr = -1; /* build array of args to past to fork, execl */ /* if see RPOST_FILTER_IN as arg, substitute the infile name */ /* if see RPOST_FILTER_OUT as first part of arg, get outfile name */ for(argon = 0, loop = 0; loop < argcount; loop++) { if(myargs->debug == TRUE) { do_debug("loop=%d argon=%d arg=%s\n", loop, argon, args[loop]); } if(strcmp(args[loop], RPOST_FILTER_IN) == 0) { /* substitute infile name */ myargs->filter_args[argon] = NULL; /* just so debug.suck looks okay */ myargs->filter_infilenr = argon++; } else if(strncmp(args[loop], RPOST_FILTER_OUT, (unsigned int) i) == 0) { /* arg should be RPOST_FILTER_OUT=filename */ if(args[loop][i] != '=') { error_log(ERRLOG_REPORT, rpost_phrases[17], args[loop], NULL); } else { myargs->filter_outfile = (char *)&(args[loop][i+1]); } } else { myargs->filter_args[argon++] = args[loop]; } } myargs->filter_argc = argon; /* the count of arguments */ myargs->filter_args[argon] = NULL; /* just to be on the safe side */ if(myargs->filter_outfile == NULL) { /* no outfile defined, use built-in default */ myargs->filter_outfile = tmpnam(NULL); error_log(ERRLOG_REPORT, rpost_phrases[9], myargs->filter_outfile, NULL); } if(myargs->filter_infilenr < 0) { error_log(ERRLOG_REPORT, rpost_phrases[10], NULL); retval = RETVAL_ERROR; } return retval; } /*--------------------------------------------------------------------*/ char *do_filter(Pargs myargs, char *filename) { char *infile = NULL; int i; myargs->filter_args[myargs->filter_infilenr] = filename; /* so this points to the right name */ if( myargs->debug == TRUE) { do_debug("ARGS:"); for(i=0;ifilter_argc;i++) { do_debug(" %d=%s", i, myargs->filter_args[i]); } do_debug("\n"); } switch((int) fork()) { case 0: /* in child, do execl */ if(execvp(myargs->filter_args[0], myargs->filter_args) == -1) { MyPerror(rpost_phrases[14]); exit(-1); /* so we don't get two running */ } break; case -1: /* should never get here */ MyPerror(rpost_phrases[15]); break; default: /* in parent, wait for child to finish */ wait(NULL); /* no status check on finish */ infile = myargs->filter_outfile; } return infile; } /*----------------------------------------------------------------------------------*/ int filter_post_article(Pargs myargs, char *filename) { char *infile = NULL; /* this is the filename that gets passed to do_article() */ int retval = RETVAL_OK; FILE *fpi_msg; #ifdef PERL_EMBED if(myargs->perl_int != NULL) { infile = filter_perl(myargs, filename); } else #endif if(myargs->filter_argc >0) { infile = do_filter(myargs, filename); } else { /* so we open up the right file */ infile = filename; } if(infile == NULL) { error_log(ERRLOG_REPORT, rpost_phrases[11], NULL); retval = RETVAL_ERROR; } else { if(myargs->show_name == TRUE) { /* show the file name */ print_phrases(myargs->status_fptr, rpost_phrases[40], infile, NULL); } if((fpi_msg = fopen(infile, "r")) == NULL) { /* skip to next article if infile don't exist */ error_log(ERRLOG_REPORT, rpost_phrases[12],NULL); } else { retval = do_article(myargs, fpi_msg); if(myargs->debug == TRUE && retval != RETVAL_OK) { do_debug("do_article() returned %d\n", retval); } fclose(fpi_msg); } } return retval; } /*--------------------------------------------------------------------------------*/ int do_batch(Pargs myargs) { int i, x, nrdone, nrok, retval; FILE *fpi_batch; char buf[MAXLINLEN+1], file[MAXLINLEN+1]; char *outfile; outfile = NULL; retval = RETVAL_OK; nrdone = nrok = 0; if((fpi_batch = fopen(myargs->batch, "r")) == NULL) { MyPerror(myargs->batch); retval = RETVAL_ERROR; } else { while((retval != RETVAL_ERROR) && (fgets(buf, MAXLINLEN, fpi_batch) != NULL)) { /* build file name */ /* if no prefix, or if this is a inn token (not a real file), just copy it */ if(myargs->prefix == NULL || (file[0] == '@' && file[strlen(file)-1] == '@')) { strcpy(file, buf); } else { strcpy(file, myargs->prefix); if(file[strlen(file)-1] != '/') { strcat(file, "/"); } strcat(file, buf); } /* strip off nl */ i = strlen(file); if(file[i-1] == '\n') { file[i-1] = '\0'; } /* some INNs put article number on line in addition to file name */ /* so lets parse through string, if find a ' ' NULL terminate at */ /* that point */ for(x=0;xdebug == TRUE) { do_debug("Article Name: %s\n", file); } retval = filter_post_article(myargs, file); nrdone++; if(retval == RETVAL_OK) { nrok++; } /* log failed uploads (dupe article is not a failed upload ) */ else if (retval == RETVAL_ARTICLE_PROB) { log_fail(myargs->batch, buf); } } if(retval == RETVAL_ERROR) { /* write out the rest of the batch file to the failed file */ do { log_fail(myargs->batch, buf); } while (fgets(buf, MAXLINLEN, fpi_batch) != NULL); } fclose(fpi_batch); if(retval != RETVAL_ERROR) { retval = (nrok == nrdone) ? RETVAL_OK : RETVAL_ARTICLE_PROB; } if(myargs->deleteyn == TRUE && retval == RETVAL_OK) { unlink(myargs->batch); print_phrases(myargs->status_fptr, rpost_phrases[13], myargs->batch,NULL); } } return retval; } /*---------------------------------------------------------------*/ void log_fail(char *batch_file, char *article) { char file[MAXLINLEN+1]; FILE *fptr; sprintf(file, "%s%s", batch_file, RPOST_FAIL_EXT); if((fptr = fopen(file, "a")) == NULL) { MyPerror(file); } else { fputs(article, fptr); fclose(fptr); } } /*------------------------------------------------------------------------------------------------*/ int do_rnews(Pargs myargs) { /* handle rnews files */ int len, nrdone, nrok, retval = RETVAL_OK; DIR *dptr; FILE *f_rnews, *f_temp; char rnews_path[PATH_MAX+1], temp_path[PATH_MAX+1], linein[MAXLINLEN]; struct dirent *dentry; sprintf(temp_path, "%s/%s", myargs->rnews_path, TEMP_ARTICLE); /* only need to do this once */ if(myargs->rnews_file == NULL || myargs->rnews_path == NULL) { error_log(ERRLOG_REPORT, rpost_phrases[39], NULL); retval = RETVAL_ERROR; } else if((dptr = opendir(myargs->rnews_path)) == NULL) { error_log(ERRLOG_REPORT, rpost_phrases[39], NULL); retval = RETVAL_ERROR; } else { if(myargs->debug == TRUE) { do_debug("Reading directory %s\n", myargs->rnews_path); } len = strlen(myargs->rnews_file); /* work our way thru the directory find our files that */ /* start with our rnews_file prefix */ while((dentry = readdir(dptr)) != NULL && retval != RETVAL_ERROR) { if(strncmp(dentry->d_name, myargs->rnews_file, len) == 0) { /* bingo, we've found one of the files*/ /* now work our way thru it and create our temp article */ /* which can be fed thru the filters and then to do_article() */ nrdone = nrok = 0; /* which article are we on */ sprintf(rnews_path, "%s/%s", myargs->rnews_path, dentry->d_name); if(myargs->debug == TRUE) { do_debug("Trying to read rnews file %s\n", rnews_path); } if((f_rnews = fopen(rnews_path, "r")) == NULL) { MyPerror(rnews_path); retval = RETVAL_ERROR; } else { f_temp = NULL; /* now work our way thru the file */ while(retval != RETVAL_ERROR && fgets(linein, MAXLINLEN, f_rnews) != NULL) { if(strncmp(linein, RNEWS_START, RNEWS_START_LEN) == 0) { if(myargs->debug == TRUE) { do_debug("Found rnews line %s", linein); } if(f_temp != NULL) { /* close out the old file, and process it */ fclose(f_temp); nrdone++; retval = filter_post_article(myargs, temp_path); if(retval == RETVAL_OK) { nrok++; } } if((f_temp = fopen(temp_path, "w")) == NULL) { MyPerror(temp_path); retval = RETVAL_ERROR; } } else if(f_temp != NULL) { /* write the line out to the file */ fputs(linein, f_temp); } } if(f_temp != NULL) { /* close out our final article */ fclose(f_temp); nrdone++; retval = filter_post_article(myargs, temp_path); if(retval == RETVAL_OK) { nrok++; } } fclose(f_rnews); if(retval != RETVAL_ERROR) { retval = (nrok == nrdone) ? RETVAL_OK : RETVAL_ARTICLE_PROB; } if(myargs->deleteyn == TRUE && retval == RETVAL_OK) { unlink(rnews_path); print_phrases(myargs->status_fptr, rpost_phrases[13], rnews_path,NULL); } } } } closedir(dptr); } return retval; } /*--------------------------------------------------------------------------------*/ /* THE strings in this routine is the only one not in the arrays, since */ /* we are in the middle of reading the arrays, and they may or may not be valid. */ /*--------------------------------------------------------------------------------*/ void load_phrases(Pargs myargs) { int error=TRUE; FILE *fpi; char buf[MAXLINLEN]; if(myargs->phrases != NULL) { if((fpi = fopen(myargs->phrases, "r")) == NULL) { MyPerror(myargs->phrases); } else { fgets(buf, MAXLINLEN, fpi); if(strncmp( buf, SUCK_VERSION, strlen(SUCK_VERSION)) != 0) { error_log(ERRLOG_REPORT, "Invalid Phrase File, wrong version\n", NULL); } else if((both_phrases = read_array(fpi, NR_BOTH_PHRASES, TRUE)) != NULL && (rpost_phrases = read_array(fpi, NR_RPOST_PHRASES, TRUE)) != NULL) { error = FALSE; } } fclose(fpi); if(error == TRUE) { /* reset back to default */ error_log(ERRLOG_REPORT, "Using default Language phrases\n",NULL); rpost_phrases = default_rpost_phrases; both_phrases = default_both_phrases; } } } /*--------------------------------------------------------------------------------*/ void free_phrases(void) { /* free up the memory alloced in load_phrases() */ if(rpost_phrases != default_rpost_phrases) { free_array(NR_RPOST_PHRASES, rpost_phrases); } if(both_phrases != default_both_phrases) { free_array(NR_BOTH_PHRASES, both_phrases); } }