ftp.nice.ch/pub/next/unix/communication/ft_bbs.1.0.s.tar.gz#/ft_bbs-1.0/nntp-com.c

This is nntp-com.c in view mode; [Download] [Up]

/* $Id$ */
#ifdef NNTPNEWS

#include "bbs.h"
#include <netinet/in.h>

extern void nntp_alrmhandler(int);
static sigjmp_buf nntp_sigalrmenv;

int nntp_connect(newsstattyp *newsstat, const confrecordtyp *confrecord)
{
  int response;
  char line[NNTP_STRLEN+1];
  
  newsstat->can_post = FALSE;
  newsstat->is_connected = FALSE;
  if (nntp_socket(newsstat,confrecord) < 0) {
    bgerror("nntp_connect","NNTP connection failed");
    return -1;
  }
  response = nntp_getresponse(line,NNTP_STRLEN,newsstat);
  switch (response) {
  case OK_CANPOST:
    newsstat->can_post = TRUE;
    break;
  case OK_NOPOST:
    newsstat->can_post = FALSE;
    break;
  default:
    return -1;
  }
  newsstat->is_connected = TRUE;
  newsstat->group_is_set = FALSE;
  return 0;
}


int nntp_socket(newsstattyp *newsstat, const confrecordtyp *confrecord)
{
  int s, n, cnt;
  char **sap;
  struct sockaddr_in sin;
  struct hostent *hostentp;
  struct servent *servp;

  if ((hostentp=gethostbyname(confrecord->nntpserver)) == NULL) {
    bgerror("nntp_socket","host %s: unknown",confrecord->nntpserver);
    return -1;
  }
  strcpy(newsstat->server,hostentp->h_name);
  if ((servp=getservbyname("nntp","tcp")) == NULL) {
    bgerror("nntp_socket","nntp/tcp: unknown service");
    return -1;
  }
  BZERO(&sin, sizeof(sin));
  sin.sin_family = hostentp->h_addrtype;
  sin.sin_port = servp->s_port;
  for (sap=hostentp->h_addr_list; sap && *sap; sap++) {
    s = socket(hostentp->h_addrtype, SOCK_STREAM, 0);
    if (s < 0) {
      bgerror("nntp_socket","socket: %m");
      return -1;
    }
    memcpy((char *)&sin.sin_addr, *sap, hostentp->h_length);
    cnt = 0;
#ifdef NNTP_CONNECT_TIMEOUT
    if (sigsetjmp(nntp_sigalrmenv,(int)FALSE) == 0) {
      setsighandler(SIGALRM, nntp_alrmhandler);
    }
    else {
      cnt++;
    }
    alarm(NNTP_CONNECT_TIMEOUT);
    n = -1;
    if (cnt < 3)  n = connect(s, (struct sockaddr *)&sin, sizeof(sin));
    alarm(0);
    setsighandler(SIGALRM, SIG_IGN);
#else
     n = connect(s, (struct sockaddr *)&sin, sizeof(sin));
#endif
    if (n == 0)  break;
    close(s);
    if (n < 0) {
      bgerror("nntp_socket","connection to NNTP server %s failed",
              newsstat->server);
    }
    s = -1;
  }
  newsstat->sock = s;
  return s;
}


void nntp_close(newsstattyp *newsstat)
{
  if (newsstat->is_connected && ! newsstat->nntp_failed) {
    nntp_ask(NULL,newsstat,"QUIT");
  }
  close(newsstat->sock);
  newsstat->is_connected = FALSE;
  return;
}


int nntp_ask(char *answer, newsstattyp *newsstat, const char *fmt, ...)
{
  int response;
  char str[NNTP_STRLEN+1];
  va_list ap;
  
  *str = '\0';
  va_start(ap, fmt);
  if (vfstrlen(fmt,ap) < NNTP_STRLEN-2) {
    vsprintf(str,fmt,ap);
  }
  va_end(ap);
  if (*str == '\0' || nntp_putline(str,newsstat) < 0)  return -1;
  response = nntp_getresponse(answer==NULL ? str : answer,NNTP_STRLEN,newsstat);
  if (response == ERR_GOODBYE || response > ERR_COMMAND) {
    newsstat->nntp_failed = TRUE;
    newsstat->group_is_set = FALSE;
    nntp_close(newsstat);
  }
  return response;
}


char *nntp_copytext(SIZE_T *len, newsstattyp *newsstat)
{
  int n, nlines;
  char *buf, *bp, *sp, *bufsafe, str[NNTP_STRLEN+1];

  if ((buf=(char *)malloc(ALLOCSTEPSIZE)) == NULL) {
    bgerror("nntp_copytext","malloc: %m");
    return NULL;
  }
  n = 1;
  bp = buf;
  nlines = 0;
  *len = 0;
  while (nntp_getline(str,NNTP_STRLEN,newsstat) >= 0) {
    sp = str;
    if (*sp == '.') {
      sp++;
      if (*sp == '\0') {
        if (nlines <= 0) {
          free(buf);
          return NULL;
        }
        *bp = '\0';
        return buf;
      }
    }
    while (*sp != '\0') {
      if (bp - buf > n*ALLOCSTEPSIZE-3) {
        n++;
        bufsafe = buf;
        if ((buf=(char *)realloc((void *)buf,n*ALLOCSTEPSIZE)) == NULL) {
          bgerror("nntp_copytext","realloc: %m");
          free(bufsafe);
          return NULL;
        }
        bp += buf - bufsafe;
      }
      *bp++ = *sp++;
      (*len)++;
    }
    *bp++ = '\n';
    (*len)++;
    nlines++;
  }
  free(buf);
  return NULL;
}


int nntp_getline(char *string, SIZE_T size, newsstattyp *newsstat)
{
  static int p=0, len=0;
  int k = 0;
  static char inbuf[NNTP_STRLEN+1];
  char c;

  do {
    if (p == len) {
      len = read(newsstat->sock,inbuf,size > NNTP_STRLEN ? NNTP_STRLEN : size);
      p = 0;
      if (len < 0)  return -1;
    }
    c = inbuf[p++];
    string[k++] = c;
  } while (c != '\n' && k < size-1);
  string[k] = '\0';
  size = strlen(string);
  size = size > 2 ? size -2 : 0;
  string[size] = '\0';
  strmaxcpy(newsstat->lastretstr,string,NNTP_STRLEN);
  return size;
}


int nntp_getresponse(char *string, SIZE_T size, newsstattyp *newsstat)
{
  if (nntp_getline(string,size,newsstat) < 0)  return -1;
  return isdigit(*string) ? atoi(string) : 0;
}


int nntp_putline(const char *string, const newsstattyp *newsstat)
{
  char outbuf[NNTP_STRLEN+1];

  strmaxcpy(outbuf,string,NNTP_STRLEN-2);
  strcat(outbuf,"\r\n");
  return write(newsstat->sock,outbuf,strlen(outbuf));
}


#ifdef NNTP_CONNECT_TIMEOUT
void nntp_alrmhandler(int sig)
{
  siglongjmp(nntp_sigalrmenv,1);
}
#endif /* NNTP_CONNECT_TIMEOUT */

#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.