/* nntpclient.c */ /* This software is copyrighted as detailed in the LICENSE file. */ #include "EXTERN.h" #include "common.h" #ifdef SUPPORT_NNTP #include "nntpinit.h" #include "INTERN.h" #include "nntpclient.h" time_t last_command_diff; char* savestr _((char*)); #ifndef USE_DEBUGGING_MALLOC char* safemalloc _((MEM_SIZE)); #endif #ifdef NNTP_HANDLE_TIMEOUT int nntp_handle_timeout _((void)); #endif int nntp_handle_nested_lists _((void)); #ifdef NNTP_HANDLE_AUTH_ERR int nntp_handle_auth_err _((void)); #endif int nntp_connect(machine,verbose) char* machine; bool_int verbose; { int response; if (nntplink.rd_fp) return 1; if (nntplink.flags & NNTP_FORCE_AUTH_NEEDED) nntplink.flags |= NNTP_FORCE_AUTH_NOW; nntplink.flags |= NNTP_NEW_CMD_OK; #if 0 try_to_connect: #endif if (verbose) { printf("Connecting to %s...",machine); fflush(stdout); } switch (response = server_init(machine)) { case NNTP_GOODBYE_VAL: if (atoi(ser_line) == response) { char tmpbuf[LBUFLEN]; if (verbose) printf("failed: %s\n",&ser_line[4]); else { sprintf(tmpbuf,"News server \"%s\" is unavailable: %s\n", machine,&ser_line[4]); nntp_init_error(tmpbuf); } response = 0; break; } case -1: if (verbose) printf("failed.\n"); else { sprintf(ser_line,"News server \"%s\" is unavailable.\n",machine); nntp_init_error(ser_line); } response = 0; break; case NNTP_ACCESS_VAL: if (verbose) printf("access denied.\n"); else { sprintf(ser_line, "This machine does not have permission to use the %s news server.\n\n", machine); nntp_init_error(ser_line); } response = -1; break; case NNTP_NOPOSTOK_VAL: if (verbose) printf("Done (but no posting).\n\n"); response = 1; break; case NNTP_POSTOK_VAL: if (verbose) printf("Done.\n") FLUSH; response = 1; break; default: if (verbose) printf("unknown response: %d.\n",response); else { sprintf(ser_line,"\nUnknown response code %d from %s.\n", response,machine); nntp_init_error(ser_line); } response = 0; break; } #if 0 if (!response) { if (handle_no_connect() > 0) goto try_to_connect; } #endif return response; } char* nntp_servername(name) char* name; { FILE* fp; if (FILE_REF(name) && (fp = fopen(name, "r")) != NULL) { while (fgets(ser_line, sizeof ser_line, fp) != NULL) { if (*ser_line == '\n' || *ser_line == '#') continue; if ((name = index(ser_line, '\n')) != NULL) *name = '\0'; name = ser_line; break; } fclose(fp); } return name; } int nntp_command(bp) char* bp; { time_t now; #if defined(DEBUG) && defined(FLUSH) if (debug & DEB_NNTP) printf(">%s\n", bp) FLUSH; #endif #if defined(NNTP_HANDLE_TIMEOUT) || defined(NNTP_HANDLE_AUTH_ERR) strcpy(last_command, bp); # ifdef NNTP_HANDLE_TIMEOUT if (!nntplink.rd_fp) return nntp_handle_timeout(); # endif # ifdef NNTP_HANDLE_AUTH_ERR if (nntplink.flags & NNTP_FORCE_AUTH_NOW) { nntplink.flags &= ~NNTP_FORCE_AUTH_NOW; return nntp_handle_auth_err(); } # endif #endif if (!(nntplink.flags & NNTP_NEW_CMD_OK)) { int ret = nntp_handle_nested_lists(); if (ret <= 0) return ret; } if (fprintf(nntplink.wr_fp, "%s\r\n", bp) < 0 || fflush(nntplink.wr_fp) < 0) #ifdef NNTP_HANDLE_TIMEOUT return nntp_handle_timeout(); #else return -2; #endif now = time((time_t*)NULL); last_command_diff = now - nntplink.last_command; nntplink.last_command = now; return 1; } int nntp_check() { int ret; int len = 0; read_it: #ifdef HAS_SIGHOLD sighold(SIGINT); #endif errno = 0; ret = (fgets(ser_line, sizeof ser_line, nntplink.rd_fp) == NULL)? -2 : 0; #ifdef HAS_SIGHOLD sigrelse(SIGINT); #endif if (ret < 0) { if (errno == EINTR) goto read_it; strcpy(ser_line, "503 Server closed connecton."); } #ifdef NNTP_HANDLE_TIMEOUT if (len == 0 && atoi(ser_line) == NNTP_TMPERR_VAL && nntp_allow_timeout && last_command_diff > 60) { ret = nntp_handle_timeout(); switch (ret) { case 1: len = 1; goto read_it; case 0: /* We're quitting, so pretend it's OK */ strcpy(ser_line, "205 Ok"); break; default: break; } } else #endif if (*ser_line <= NNTP_CLASS_CONT && *ser_line >= NNTP_CLASS_INF) ret = 1; /* (this includes NNTP_CLASS_OK) */ else if (*ser_line == NNTP_CLASS_FATAL) ret = -1; /* Even though the following check doesn't catch all possible lists, the * bit will get set right when the caller checks nntp_at_list_end(). */ if (atoi(ser_line) == NNTP_LIST_FOLLOWS_VAL) nntplink.flags &= ~NNTP_NEW_CMD_OK; else nntplink.flags |= NNTP_NEW_CMD_OK; len = strlen(ser_line); if (len >= 2 && ser_line[len-1] == '\n' && ser_line[len-2] == '\r') ser_line[len-2] = '\0'; #if defined(DEBUG) && defined(FLUSH) if (debug & DEB_NNTP) printf("<%s\n", ser_line) FLUSH; #endif #ifdef NNTP_HANDLE_AUTH_ERR if (atoi(ser_line) == NNTP_AUTH_NEEDED_VAL) { ret = nntp_handle_auth_err(); if (ret > 0) goto read_it; } #endif return ret; } bool nntp_at_list_end(s) char* s; { if (!s || (*s == '.' && (s[1] == '\0' || s[1] == '\r'))) { nntplink.flags |= NNTP_NEW_CMD_OK; return 1; } nntplink.flags &= ~NNTP_NEW_CMD_OK; return 0; } int nntp_gets(bp, len) char* bp; int len; { int n; read_it: #ifdef HAS_SIGHOLD sighold(SIGINT); #endif errno = 0; n = (fgets(bp, len, nntplink.rd_fp) == NULL)? -2 : 0; #ifdef HAS_SIGHOLD sigrelse(SIGINT); #endif if (n < 0) { if (errno == EINTR) goto read_it; nntplink.flags |= NNTP_NEW_CMD_OK; return n; } n = strlen(bp); if (n > 0) { /* check for CR/LF split across the buffer boundry */ if (bp[n-1] == '\r') bp[n-1] = '\0'; else if (bp[n-1] == '\n') { if (n > 1 && bp[n-2] == '\r') bp[n-2] = '\0'; else bp[n-1] = '\0'; return 1; } } return 0; } void nntp_close(send_quit) bool_int send_quit; { if (send_quit && nntplink.wr_fp != NULL && nntplink.rd_fp != NULL) { if (nntp_command("QUIT") > 0) nntp_check(); } /* the nntp_check() above might have closed these already. */ if (nntplink.wr_fp != NULL) { fclose(nntplink.wr_fp); nntplink.wr_fp = NULL; } if (nntplink.rd_fp != NULL) { fclose(nntplink.rd_fp); nntplink.rd_fp = NULL; } nntplink.flags |= NNTP_NEW_CMD_OK; } #endif /* SUPPORT_NNTP */