/* * nntp.c: the protocol workhorse module for newsfetch */ #include #include #include #include #include #include #include #include #include #include #include #include "newsfetch.h" extern int terminate, wait_after_articles, wait_for_time, articles_fetched; extern int last_than_current, first_article, max_article, news_target; extern int timeout, article_fetching; extern char dirname[100], group[100], pipe_command[100]; extern FILE *rcfp, *rctmpfp, *socket_fp[2]; char *header; #define MAXBUFSIZE 1000 char command_buf[MAXBUFSIZE + 1]; /* lots of protos */ void read_nntp_data(void); int get_error(char *buf); int get_error_noprint(char *buf); int get_error_strmsg(char *buf); int set_article_number(char *buf); FILE * get_newsfilefd(void); int fetch_article(FILE * pipefp); /* * this function is called repeatedly to buffer in news streams */ void read_nntp_data() { alarm(timeout); fgets(command_buf, MAXBUFSIZE, socket_fp[1]); alarm(0); } /* * this is a dummy flush routine - very common */ int set_reader_mode() { read_nntp_data(); fprintf(socket_fp[0], "MODE READER\n"); read_nntp_data(); return (get_error(command_buf)); } /* * does what it says */ int get_error(char *buf) { int result; sscanf(buf, "%d", &result); if (result >= 200 && result < 300) return (1); /* * Print error message */ fprintf(stderr, "%s", buf); return (0); } int get_error_noprint(char *buf) { int result; sscanf(buf, "%d", &result); if (result >= 200 && result < 300) return (1); return (0); } int get_error_strmsg(char *buf) { int result, space = 0x20; char *errMsg; sscanf(buf, "%d", &result); if (result >= 200 && result < 300) return (1); errMsg = strchr(buf, space); /* * Print error message with a leading space */ fprintf(stderr, "%s", errMsg); return (0); } int set_article_number(char *buf) { int result; sscanf(buf, "%d %d", &result, &first_article); return (1); } FILE * get_newsfilefd() { char news_filename[200]; FILE * newsfp; if (news_target == 2 || news_target == 3) return (stdout); if (news_target == 4) { newsfp = popen(pipe_command, "w"); if (newsfp == NULL) perror(pipe_command); return (newsfp); } strcpy(news_filename, dirname); if (strlen(dirname)) strcat(news_filename, "/"); strcat(news_filename, group); #ifdef DEBUG fprintf(stderr, "maildir %s\n", news_filename); #endif /* */ if ((newsfp = fopen(news_filename, "a+")) == NULL) fprintf(stderr, "Can not create news file...aborting\n"); return (newsfp); } int get_next_group() { char *tmp; int items_read, comment = 1; max_article = -1; while (comment) { tmp = fgets(command_buf, MAXBUFSIZE, rcfp); if (tmp == NULL) return (0); #ifdef DEBUG fprintf(stderr, "get_next_group: %s\n", command_buf); #endif /* */ for (items_read = 0; command_buf[items_read] == 0x20; items_read++); if (command_buf[items_read] != '#' && command_buf[items_read] != '\n') comment = 0; else fprintf(rctmpfp, "%s", command_buf); } items_read = sscanf(command_buf, "%s %d %d", group, &first_article, &max_article); if (items_read < 2) return (0); return (items_read); } int check_group() { int first_art, last_art, total_art, tmp; fprintf(stderr, "%s: ", group); fprintf(socket_fp[0], "GROUP %s\n", group); read_nntp_data(); #ifdef DEBUG fprintf(stderr, "fetch group: %s\n", command_buf); #endif /* */ if (!get_error_strmsg(command_buf)) { first_article--; return (0); } sscanf(command_buf, "%d %d %d %d", &tmp, &total_art, &first_art, &last_art); if (first_article > last_art) { fprintf(stderr, "No new articles\n"); first_article = last_art; return (0); } if (first_article < first_art) first_article = first_art; if (max_article != -1) { if ((last_art - first_article) + 1 > max_article) first_article = last_art - max_article + 1; } fprintf(socket_fp[0], "STAT %d\n", first_article); read_nntp_data(); while (!get_error_noprint(command_buf)) { first_article++; /* * Some news server appear to give the article number of * expired articles, check for the last_art */ if (first_article > last_art) { fprintf(stderr, "No new articles: Should not happen\n"); first_article = last_art; return (0); } fprintf(socket_fp[0], "STAT %d\n", first_article); read_nntp_data(); } fprintf(stderr, "articles %d to %d\n", first_article, last_art); return (1); } int fetch_group() { FILE * newsfp; int tmp = 1; if ((newsfp = get_newsfilefd()) == NULL) { /* * This is perfect even if article number became invalid * since in next run ++ operation will make it valid * article and save STAT time */ first_article--; return (-1); } /* NOTE: during the debug process it was suggested that i create this double braced assignment */ for(; (tmp = fetch_article(newsfp)) && terminate;); first_article = last_than_current; if (news_target < 3) fclose(newsfp); if (news_target == 4) pclose(newsfp); #ifndef NO_STATUS_METER if (isatty(2)) fprintf(stderr, " %c", 0xd); #endif /* */ if (terminate) return (1); return (-1); } int fetch_article(FILE * pipefp) { int check_header = 1; /* * Limit is article_fetched and wait_for articles are interger * In rare case, article fetched can be wrap around */ if (wait_after_articles && articles_fetched == wait_after_articles) { if (isatty(2)) fprintf(stderr, "Waiting for %d seconds%c", wait_for_time, 0xd); articles_fetched = 0; sleep(wait_for_time); if (isatty(2)) fprintf(stderr, " %c", 0xd); } fprintf(socket_fp[0], "ARTICLE\n"); read_nntp_data(); if (!get_error(command_buf)) return (0); articles_fetched++; if (news_target == 3) { /* * forget about old pipefp, make it more simple */ pipefp = popen(pipe_command, "w"); if (pipefp == NULL) { perror(pipe_command); return (-1); } } /* * Make it little fast */ fprintf(socket_fp[0], "NEXT\n"); article_fetching = 1; #ifndef NO_STATUS_METER if (isatty(2)) { fprintf(stderr, " %c", 0xd); fprintf(stderr, "%d%c", first_article, 0xd); } #endif /* */ read_nntp_data(); /* * Put any date, require by many mail reader */ fprintf(pipefp, "From localhost Sat Apr 26 18:57:03 WAT 1997\n"); while (command_buf[0] != '.' || command_buf[1] != 13) { if (command_buf[0] == '.' && command_buf[1] == '.') command_buf[1] = 0x20; if (command_buf[strlen(command_buf) - 2] == 0xd || command_buf[strlen(command_buf) - 2] == 0x0a) command_buf[strlen(command_buf) - 2] = '\0'; if (command_buf[strlen(command_buf) - 1] == 0xd || command_buf[strlen(command_buf) - 1] == 0x0a) command_buf[strlen(command_buf) - 1] = '\0'; fprintf(pipefp, "%s\n", command_buf); if (check_header && (strncasecmp(command_buf, "Newsgroups:", 10)) == 0) { fprintf(pipefp, "%s: %s\n", NEWSFETCH_HEADER_INCL, group); check_header = 0; } read_nntp_data(); } fprintf(pipefp, "\n"); if (news_target == 3) pclose(pipefp); last_than_current = first_article; article_fetching = 0; if (terminate) { read_nntp_data(); if (!get_error_noprint(command_buf)) return (0); set_article_number(command_buf); } return (1); } void get_group_list() { char groupname[100]; fprintf(stderr, "\nList of NewsGroups:\n"); fprintf(socket_fp[0], "LIST\n"); read_nntp_data(); if (!get_error_strmsg(command_buf)) exit(1); read_nntp_data(); sscanf(command_buf, "%s", groupname); while (command_buf[0] != '.' || command_buf[1] != 13) { fprintf(stderr, "%s\n", groupname); read_nntp_data(); sscanf(command_buf, "%s", groupname); } exit(1); } void send_quit() { fprintf(socket_fp[0], "QUIT\n"); read_nntp_data(); } void fill_tmpfile() { char *tmp; while ((tmp = fgets(command_buf, MAXBUFSIZE, rcfp)) != NULL) fprintf(rctmpfp, "%s", command_buf); }