Retrieving documents with NNTP This agent conforms to W3A/A. It uses some utility routines that are not shown. The agents handles nntp: and news: URLs. [[news:*]] retrieves list of all newsgroups. [[news:group]] retrieves list of articles in the group. [[news:artID]] retrieves article with ID. [[news:group/artnr]] retrieves n'th article in group. [[nntp://host:port/group/artnr]] The agent gets the server from the NNTPSERVER environment variable or from a compiled-in default. <<*>>= static char copyright[] = "Copyright NBBI, Den Haag, 1995"; /* Author: Bert Bos */ #define USE_POLL 0 #include #if USE_POLL #include #endif #include #include #include #include #include /* To find who we are */ #include #include /* connectTCP() */ #include /* String and heap functions */ #include /* URL parsing */ #include /* Read/parse MIME headers */ #ifndef howmany #define howmany(x,y) (((x)+((y)-1))/(y)) #endif #define NRBITS (sizeof(int) * 8) /* 8 bits per byte */ #ifndef NNTPSERVER #define NNTPSERVER "news" #endif typedef enum {AllGroups, ArtList, ArtID, ArtNr} Mode; char *server; /* NNTP server */ static Strip news, nntp, star; /* = "news", "nntp", "*" */ static struct { FILE *f; Mode mode; char *group; char *id; int nr; } conn_info[FD_SETSIZE]; EXPORT Bool initNNTP(char ***protocols, int *nrprotocols) { static char *protos[] = {"news", "nntp"}; *protocols = protos; *nrprotocols = XtNumber(protos); if (! (server = getenv("NNTPSERVER"))) server = NNTPSERVER; news = str2strip("news"); nntp = str2strip("nntp"); star = str2strip("*"); return TRUE; } EXPORT int openNNTP(const char *url, int method, int flags, const char *referer) { URI uri; char *host, *port, *p; int s; if (! URL_parse(url, &uri)) { errno = EURL; /* Bad URL syntax */ return -1; } assert(uri.scheme == nntp || uri.scheme == news); if (uri.scheme == news) { host = server; port = "nntp"; } else { host = strip2str(uri.host); port = uri.port : strip2str(uri.port) : "nntp"; } if ((s = connectTCP(host, port, (flags & O_NONBLOCK) != 0)) == -1 && errno != EINPROGRESS) { return -1; /* Could not connect */ } if (!(conn_info[s].f = fdopen(s, "r+"))) return -1; /* I/O error */ if (uri.path == star) { conn_info[s].mode = AllGroups; conn_info[s].group = NULL; conn_info[s].id = NULL; } else if (strchr(strip2str(uri.path, '@'))) { conn_info[s].mode = ArtId; conn_info[s].group = NULL; conn_info[s].id = strdup(strip2str(uri.path)); } else if (strchr(strip2str(uri.path), '/')) { conn_info[s].mode = ArtNr; conn_info[s].group = tokenize(strdup(strip2str(uri.path)). "/", &p); conn_info[s].id = NULL; conn_info[s].nr = atoi(tokenize(p, "", &p)); } else { conn_info[s].mode = ArtList; conn_info[s].group = strdup(strip2str(uri.path)); conn_info[s].id = NULL; } return s; } EXPORT Bool doneNNTP(int fd) { ... } EXPORT int peekNNTP(int fd) { #if USE_POLL struct pollfd fds[1]; fds[0].fd = fd; fds[0].events = POLLNORM; /* return: -1 = err; 0 = timed out; 1 = input available */ return poll(fds, 1, 0); #else /* USE_POLL */ int mask[howmany(FD_SETSIZE, NRBITS)]; struct timeval timeout; int n, i; timeout.tv_sec = 0; timeout.tv_usec = 0; for (i = 0; i < XtNumber(mask); i++) mask[i] = 0; mask[fd/NRBITS] |= 1 << (fd % NRBITS); if ((n = select(fd + 1, mask, NULL, NULL, &timeout)) == -1) return -1; return n; /* 0 or 1 */ #endif /* USE_POLL */ } EXPORT int readNNTP(int fd, char *buf, size_t nbytes) { ... } EXPORT int writeNNTP(int fd, const char *buf, size_t nbytes) { ... } EXPORT Bool infoNNTP(int fd, W3ADocumentInfo *buf) { ... } EXPORT Bool closeNNTP(int fd) { dispose(conn_info[fd].group); dispose(conn_info[fd].id); return fclose(conn_info[fd].f) != -1; } EXPORT Bool deleteNNTP(const char *url) { errno = ENYI; /* Not yet implemented */ return FALSE; }