home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-02-21 | 37.9 KB | 1,741 lines |
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <time.h>
- #include <ctype.h>
- #include <string.h>
-
- #include "kernel.h"
- #include "global.h"
- #include "timer.h"
- #include "cmdparse.h"
- #include "netuser.h"
- #include "nntp.h"
- #include "smtp.h"
- #include "domain.h"
- #include "misc.h"
- #include "tcp.h"
- #include "mbuf.h"
- #include "arc.h"
- #include "Terminal.h"
- #include "vterm.h"
-
- #include "alarm.h"
- #include "flex.h"
- #include "os.h"
- #include "swis.h"
- #include "visdelay.h"
-
- #include "Reader.h"
-
- typedef struct spdstat_str
- {
- int start_t;
- int last_t;
- int count;
- int speed;
- int samples;
- } spdstat_str;
-
- void spdstat_start(spdstat_str *sp);
- void spdstat_restart(spdstat_str *sp);
- int spdstat_update(spdstat_str *sp, int count);
- int spdstat_end(spdstat_str *sp);
-
- /*
- * In nntpidhist.c
- */
- time_t time_aton(char *s);
- char *time_ntoa(char *buf, time_t t);
- time_t time_readgmt(void);
-
- typedef struct idhist_str *idhistory;
-
- idhistory idhist_init(int size);
- void idhist_kill(idhistory hist);
- int idhist_addid(idhistory hist, char *id, time_t t);
- int idhist_checkid(idhistory hist, char *id);
- int idhist_save(idhistory hist, char *file, int maxage);
- idhistory idhist_load(char *file /*, int maxage */);
- char *idhist_trimstr(char *s);
- char *idhist_msgid(idhistory hist, int id, char *buf);
- int idhist_numids(idhistory hist);
-
- #define NNTPMAXLEN 510
- #define BATCH_MAX 16
-
- #define ID_LEN 28
-
- #define NN_CMD 0
- #define NN_DAT 1
- #define NN_RDY 2
-
- #define NN_OPEN 1
- #define NN_NEWG 2
- #define NN_NEWN 3
- #define NN_GETN 4
- #define NN_BYNUM 5
- #define NN_SELG 6
- #define NN_GNUM 7
- #define NN_NEXT_STAGE 8
- #define NN_POST 9
- #define NN_PREARTSEND_STAGE 10
- #define NN_POSTARTSEND_STAGE 11
- #define NN_QUIT 12
-
- static struct nntpservers
- {
- struct timer nntpcli_t;
- char *name;
- char *abbr;
- char *temp;
- int lowtime, hightime; /* for connect window */
- struct nntpservers *next;
- struct tcb *tcb; /* tcp task control buffer */
- int32 ipdest; /* address of forwarding system */
- char state; /* state machine placeholder */
- char stage; /* another state machine placeholder */
- char buf[NNTPMAXLEN];/* Input buffer */
- char cntovr; /* Flag to determin of dot esc needs to be done */
- int cnt; /* Length of input buffer */
- FILE *input1;
- FILE *input0;
- FILE *output;
- FILE *newsfile;
- FILE *id_file;
- idhistory history;
- int histsaved;
- int batch;
- time_t thisfeed; /* Time in GMT that this news feed started */
- time_t lastfeed; /* Time in GMT that last news feed started */
- long file_len;
- int msg_tot;
- char goodrcpt; /* are any of the rcpt ok */
- char cts; /* clear to send state indication */
- int rcpts; /* number of unacked rcpt commands */
- struct list *errlog;
- int lastread;
- struct directory *topost;
- long rnewspos;
- Terminal *window;
- int ids_count;
- spdstat_str ids_spd;
- int art_count;
- spdstat_str art_spd;
- };
-
- struct directory
- {
- struct directory *next;
- char *name;
- };
-
- #define NULLNNTP (struct nntpservers *)NULL
-
- struct nntpservers *Nntpservers = NULLNNTP;
-
- static void nntptick(void *);
- static int doadds(int, char **);
- static int dobatch(int, char **);
- static int dodirect(int, char **);
- static int dodrops(int, char **);
- static int dodups(int, char **);
- static int dofudge(int, char **);
- static int dokicks(int, char **);
- static int dolists(int, char **);
- static int donewgrps(int argc, char **argv);
- static int dostop(int, char **);
- static int dotrim(int, char **);
- static int donntptrace(int, char **);
- static int dofudge(int argc, char *argv[]);
-
- static void quit(struct nntpservers *, BOOL);
- static void nntp_rec(struct tcb *, int16);
- static void nntp_cts(struct tcb *, int16);
- static void nntp_state(struct tcb *, char, char);
- static void sendit(struct nntpservers *, char *, ...);
-
- static int check_files(char *abbr);
- static int fillgroupbuf(FILE *fp, char *buf, int len);
-
- static int ReaderS_Hist(struct nntpservers *cb);
- static BOOL have_we(char *line, struct nntpservers *cb);
- static int history_init(struct nntpservers *cb);
- static int history_close(struct nntpservers *cb);
- static int history_open(struct nntpservers *cb);
- static void nntp_shutdown(void);
-
- extern int lport; /* local port placeholder */
-
- static int nntptrace = 0; /* used for trace level */
- static int newgroups = 1; /* Update new groups listing */
-
- static char quitcmd[] = "QUIT\r\n";
-
- static char *duptab[] = { "auto", "ReaderS", "history" };
-
- #define DUP_AUTO 0
- #define DUP_READERS 1
- #define DUP_HIST 2
-
- static int dup_method = DUP_AUTO;
- static int trim_age = 72;
- static int fudge = 0;
- static int batch = 4;
- static BOOL direct = FALSE;
-
- struct cmds nntpcmds[] = {
- "addserver", doadds, 4, "nntp addserver <name> <time> <abbr>", NULLCHAR,
- "batch", dobatch, 1, "nntp batch <n>", NULLCHAR,
- "direct", dodirect, 1, "nntp direct <on|off>", NULLCHAR,
- "dropserver", dodrops, 2, "nntp dropserver <name|abbr>", NULLCHAR,
- "duplicates", dodups, 1, "nntp duplicates [<auto|readers|history>]", NULLCHAR,
- "fudge", dofudge, 1, "nntp fudge [<time>]", NULLCHAR,
- "kick", dokicks, 2, "nntp kick <name|abbr>", NULLCHAR,
- "listserver", dolists, 0, NULLCHAR, NULLCHAR,
- "newgroups", donewgrps, 1, "nntp newsgroups [y|n]", NULLCHAR,
- "stop", dostop, 0, "nntp stop <name|abbr>", NULLCHAR,
- "trim", dotrim, 0, "nntp trim <hours>", NULLCHAR,
- "trace", donntptrace, 0, NULLCHAR, NULLCHAR,
- NULLCHAR,
- };
-
- int donntp(int argc, char **argv)
- {
- return subcmd(nntpcmds,argc,argv);
- }
-
- static int donntptrace(int argc, char **argv)
- {
- if (argc < 2)
- cwprintf(NULL, "%d\r\n", nntptrace);
- else
- nntptrace = atoi(argv[1]);
- return 0;
- }
-
- static int donewgrps(int argc, char **argv)
- {
- if (argc < 2)
- {
- cwprintf(NULL, "NNTP - new groups list update %s\n",(newgroups)?"on":"off");
- }
- else
- {
- if (*argv[1]=='y' || *argv[1]=='Y')
- newgroups = 1;
- else if (*argv[1]=='n' || *argv[1]=='N')
- newgroups = 0;
- else
- return 1;
- }
- return 0;
- }
-
- static int dofudge(int argc, char *argv[])
- {
- if (argc < 2)
- {
- cwprintf(NULL, "NNTP - Fudge factor %d\n", fudge);
- }
- else
- {
- fudge = abs(atoi(argv[1]));
- }
- return 0;
- }
-
- static int dobatch(int argc, char *argv[])
- {
- if (argc < 2)
- {
- cwprintf(NULL, "NNTP - Batch %d\n", batch);
- }
- else if (atoi(argv[1]) > 0 && atoi(argv[1]) < BATCH_MAX)
- {
- batch = abs(atoi(argv[1]));
- }
- return 0;
- }
-
- static int dotrim(int argc, char *argv[])
- {
- if (argc < 2)
- cwprintf(NULL, "NNTP - Trim history to %d hours\n", trim_age);
- else
- trim_age = atoi(argv[1]);
-
- if (trim_age < (fudge+3600)/3600)
- trim_age = (fudge+3600)/3600;
-
- return 0;
- }
-
- static int dodirect(int argc, char *argv[])
- {
- if (argc < 2)
- {
- cwprintf(NULL, "NNTP - direct %s\n", direct ? "on" : "off");
- }
- else if (stricmp(argv[1], "on") == 0)
- {
- direct = TRUE;
- }
- else
- {
- direct = FALSE;
- }
- return 0;
- }
-
- static int dodups(int argc, char *argv[])
- {
- int loop;
-
- if (argc < 2)
- {
- cwprintf(NULL, "%s\n", duptab[dup_method]);
- }
- else
- {
- for (loop = 0; loop < 3; loop++)
- {
- if (strnicmp(argv[1], duptab[loop], MIN(strlen(argv[1]), strlen(duptab[loop]))) == NULL)
- break;
- }
- if (loop == 3)
- loop = 0;
- dup_method = loop;
- }
- return 0;
- }
-
- static int doadds(int argc, char *argv[])
- {
- struct nntpservers *np;
-
- for(np = Nntpservers; np != NULLNNTP; np = np->next)
- if (stricmp(np->name, argv[1]) == 0)
- break;
- if (np == NULLNNTP)
- {
- if (check_files(argv[3]))
- {
- np = (struct nntpservers *) calloc(1, sizeof(struct nntpservers));
- np->name = strdup(argv[1]);
- np->abbr = strdup(argv[3]);
- np->ipdest = resolve(argv[1]);
- np->next = Nntpservers;
- Nntpservers = np;
- np->lowtime = np->hightime = -1;
- np->nntpcli_t.func = nntptick; /* what to call on timeout */
- np->nntpcli_t.arg = (void *) np;
- np->state = NN_RDY;
- np->stage = NN_OPEN;
- np->input0 = NULL;
- np->input1 = NULL;
- np->output = NULL;
- np->newsfile = NULL;
- np->id_file = NULL;
- np->history = NULL;
- np->histsaved = 1;
-
- /* -ID-
- * Add code to chekc that global IDs are initialised and that
- * ReaderS ID are incorporated if needed
- */
- history_init(np);
-
- if (dup_method == DUP_AUTO || dup_method == DUP_READERS)
- ReaderS_Hist(np);
-
- /* set timer duration */
- set_timer(&(np->nntpcli_t), atol(argv[2]) * 1000L);
- start_timer(&(np->nntpcli_t));
- }
- else
- {
- cwprintf(NULL, "Error: Can't open %sGroup file for this server\r\n",np->abbr);
- }
- }
-
- return 0;
- }
-
- static int dodrops(int argc, char *argv[])
- {
- struct nntpservers *np, *npprev = NULLNNTP;
- for(np = Nntpservers; np != NULLNNTP; npprev = np, np = np->next)
- {
- if (stricmp(np->name, argv[1]) == 0 || stricmp(np->abbr, argv[1]) == 0)
- {
- stop_timer(&np->nntpcli_t);
- free(np->name);
- free(np->abbr);
- if (np->input1 != NULL)
- fclose(np->input1);
- if (np->input0 != NULL)
- fclose(np->input0);
- if (np->output != NULL)
- fclose(np->output);
- if (np->newsfile != NULL)
- fclose(np->newsfile);
- np->msg_tot = 0;
- if(npprev != NULLNNTP)
- npprev->next = np->next;
- else
- Nntpservers = np->next;
- free((char *)np);
- return 0;
- }
- }
- cwprintf(NULL, "NNTP - No such server enabled.\r\n");
- return 0;
- }
-
- static int dokicks(int argc, char *argv[])
- {
- struct nntpservers *np;
- for (np = Nntpservers; np != NULLNNTP; np = np->next)
- {
- if (stricmp(np->name, argv[1]) == 0 || stricmp(np->abbr, argv[1]) == 0)
- {
- /* If the timer is not running, the timeout function has
- already been called and we don't want to call it again. */
- if (run_timer(&np->nntpcli_t))
- {
- np->state = NN_CMD;
- np->stage = NN_OPEN;
- stop_timer(&np->nntpcli_t);
- nntptick((void *)np);
- }
- else
- {
- cwprintf(NULL, "NNTP - Can't restart\r\n");
- }
- return 0;
- }
- }
- cwprintf(NULL, "NNTP - No such server enabled.\r\n");
- return 0;
- }
-
- static int dostop(int argc, char *argv[])
- {
- struct nntpservers *np;
- for(np = Nntpservers; np != NULLNNTP; np = np->next)
- {
- if (stricmp(np->name, argv[1]) == 0 || stricmp(np->abbr, argv[1]) == 0)
- {
- quit(np, FALSE);
- start_timer(&np->nntpcli_t);
- return 0;
- }
- }
- cwprintf(NULL, "NNTP - No such server enabled.\r\n");
- return 0;
- }
-
- static struct directory *make_dir(char *dir)
- {
- struct directory *list=NULL, *entry;
- char name[256];
-
- for (filedir(dir, 0, name); *name; filedir(dir, 1, name))
- {
- if (entry = (struct directory *) malloc(sizeof(struct directory)), entry == 0)
- break;
- entry->name = strdup(name);
- entry->next = list;
- list = entry;
- }
- return list;
- }
-
- static void kill_dir(struct directory *dir)
- {
- struct directory *entry;
-
- for (entry = dir; entry; )
- {
- dir = entry->next;
- free(entry->name);
- free(entry);
- entry = dir;
- }
- }
-
- static void nntptick(void *tp)
- {
- char title[256];
- struct socket lsocket, fsocket;
- register struct nntpservers *cb;
-
- cb = (struct nntpservers *) tp;
- if (cb == NULL)
- return;
- if (cb->state != NN_CMD)
- return;
-
- sprintf(title, "NNTP - %s", cb->name);
- cb->window = Window_Open(NULL, title, term_NO_INPUT | term_DONT_DESTROY);
- vterm_visible(cb->window->vt, 40, 8);
- vterm_setflags(cb->window->vt, VTSW_WRAP, VTSW_WRAP);
- /* setup the socket */
- fsocket.address = cb->ipdest;
- fsocket.port = NNTP_PORT;
- lsocket.address = ip_addr; /* our ip address */
- lsocket.port = lport++; /* next unused port */
-
- if (nntptrace)
- {
- cwprintf(cb->window, "NNTP daemon entered\r\n",inet_ntoa(fsocket.address));
- }
-
- if (nntptrace > 1)
- {
- cwprintf(cb->window, "NNTP trying Connection to %s\r\n",inet_ntoa(fsocket.address));
- }
-
- stop_timer(&cb->nntpcli_t);
-
- cb->batch = 0;
- cb->thisfeed = time_readgmt();
-
- /*
- * History is allready loaded
- * but IDs are writen as we go anyway
- * just in case something goes wrong with computer...
- */
- history_open(cb);
-
- /* open nntp connection */
- cb->stage = NN_OPEN; /* init stage placeholder */
- cb->state = NN_CMD; /* init state placeholder */
- cb->tcb = open_tcp(&lsocket, &fsocket, TCP_ACTIVE, tcp_window, (void(*)())nntp_rec, (void(*)())nntp_cts, (void(*)())nntp_state, 0, (char *)cb);
- cb->tcb->user = (char *)cb; /* Upward pointer */
-
- spdstat_start(&cb->ids_spd);
- spdstat_start(&cb->art_spd);
- cb->ids_count = 0;
- cb->art_count = 0;
- }
-
- BOOL nntp_select(struct nntpservers *cb)
- {
- BOOL ret = FALSE;
- char buffer[256];
-
- if( !cb->input0 )
- {
- sprintf(buffer, "<NNTP$Dir>.%sNGroup", cb->abbr);
- cb->input0 = fopen(buffer, "rb+");
- }
-
- if (cb->input0)
- {
- if (fgets(buffer, LINELEN - 1, cb->input0) != 0 && strlen(buffer) > 12)
- {
- strtok(buffer, " \n");
- cb->lastread = atoi(strtok(NULL, " \n"));
-
- if (nntptrace > 1)
- {
- cwprintf(cb->window, "NNTP - Selecting group %s\r\n", buffer);
- }
- rip(buffer);
- sendit(cb,"GROUP %s\r\n", buffer);
- cb->stage = NN_SELG;
- cb->state = NN_CMD;
- ret = TRUE;
- }
- else
- {
- fclose(cb->input0);
- cb->input0 = NULL;
- cb->stage = NN_QUIT;
- cb->state = NN_RDY;
- }
- }
- return(ret);
- }
-
- static BOOL nntp_getnews(register struct nntpservers *cb, char *list)
- {
- BOOL ret = FALSE;
- char buffer[256], line[NNTPMAXLEN + 1];
-
- if (cb->input1 == NULL && cb->batch == 0)
- {
- sprintf(buffer, "<NNTP$Dir>.%s%s", cb->abbr, list);
- cb->input1 = fopen(buffer, "r");
- if (cb->input1!=NULL && !strcmp(list, "Get"))
- cwprintf(cb->window, "NNTP - Fetching requested articles\r\n");
- }
-
- if (cb->input1 != NULL)
- {
- while (cb->batch < batch && cb->input1 != NULL && !feof(cb->input1))
- {
- while(fgets(line, LINELEN - 1, cb->input1) != NULL && have_we(line, cb))
- ;
- if (feof(cb->input1))
- {
- fclose(cb->input1);
- cb->input1 = NULL;
- sprintf(buffer, "<NNTP$Dir>.%s%s", cb->abbr, list);
- remove(buffer);
- }
- else
- {
- rip(line);
- sendit(cb, "ARTICLE %s\r\n", line);
- cb->stage = NN_GETN;
- cb->state = NN_CMD;
- (cb->batch)++;
- if (nntptrace > 2)
- {
- cwprintf(cb->window, "NNTP - Asking for article %s\r\n", line);
- }
- }
- }
- }
- if (cb->batch > 0)
- {
- cb->stage = NN_GETN;
- cb->state = NN_CMD;
- ret = TRUE;
- }
- else
- {
- cb->stage = NN_NEWN;
- cb->state = NN_RDY;
- ret = FALSE;
- }
- return(ret);
- }
-
- static BOOL nntp_newnews(register struct nntpservers *cb)
- {
- BOOL ret = FALSE;
- char buffer[256], line[NNTPMAXLEN + 1];
- char td[20];
-
- if (cb->input0 == NULL)
- {
- sprintf(buffer, "<NNTP$Dir>.%sGroup", cb->abbr);
- cb->input0 = fopen(buffer, "r");
- }
-
- if (cb->input0 != NULL)
- {
- if (fillgroupbuf(cb->input0, line, NNTPMAXLEN-30))
- {
- time_ntoa(td, cb->lastfeed-fudge);
- sendit(cb, "NEWNEWS %s %s GMT\r\n", line, td);
- cb->stage = NN_NEWN;
- cb->state = NN_CMD;
-
- if (nntptrace > 1)
- cwprintf(cb->window, "NNTP - Checking group(s) %s\r\n", line);
-
- ret = TRUE;
- }
- else
- {
- FILE *temp;
-
- fclose(cb->input0);
- cb->input0 = NULL;
-
- sprintf(buffer, "<NNTP$Dir>.%sLast", cb->abbr);
- if (temp = fopen(buffer, "w"), temp != NULL)
- {
- time_ntoa(td, cb->thisfeed);
- fprintf(temp, "%s\n", td);
- fclose(temp);
- ret = FALSE;
- }
- cb->state = NN_RDY;
- cb->stage = NN_QUIT /* NN_BYNUM */;
- }
- }
- else
- {
- cb->state = NN_RDY;
- cb->stage = NN_QUIT /* NN_BYNUM */;
- }
- return(ret);
- }
-
- static BOOL nntp_newgroups(register struct nntpservers *cb)
- {
- BOOL ret = FALSE;
- char buffer[256];
- FILE *temp;
- char td[20];
-
- sprintf(buffer, "<NNTP$Dir>.%sLast", cb->abbr);
- if (temp = fopen(buffer, "r"), temp != NULL)
- {
- cb->lastfeed = 0;
-
- if (fgets(td, 19, temp) != NULL)
- {
- int n;
- /*
- * In case of old style last file
- */
- if (n = strlen(td), n<8)
- {
- strcat(td, " ");
- fgets(td+n, 10, temp);
- }
- cb->lastfeed = time_aton(td);
- }
- if (cb->lastfeed==0)
- cb->lastfeed = time_readgmt()-(24*60*60);
-
- fclose(temp);
- }
-
- if (newgroups)
- {
- time_ntoa(td, cb->lastfeed-fudge);
-
- sendit(cb, "NEWGROUPS %s GMT\r\n", td);
- ret = TRUE;
- if (nntptrace > 1)
- cwprintf(cb->window, "NNTP - Checking for new groups since last call\r\n");
- }
- return(ret);
- }
-
- static BOOL nntp_next_command(register struct nntpservers *cb)
- {
- BOOL ret = FALSE;
-
- switch(cb->stage)
- {
- case NN_POST:
- sendit(cb, "POST\r\n");
- cb->state = NN_CMD;
- cb->stage = NN_POST;
- ret = TRUE;
- break;
-
- case NN_NEWG:
- if (nntp_newgroups(cb))
- {
- cb->state = NN_CMD;
- ret = TRUE;
- }
- else
- {
- cb->state = NN_RDY;
- cb->stage = NN_NEWN;
- ret = FALSE;
- }
- break;
-
- case NN_NEWN:
- if (nntp_newnews(cb))
- {
- cb->state = NN_CMD;
- ret = TRUE;
- }
- else if (nntp_getnews(cb, "Get"))
- {
- cb->state = NN_CMD;
- ret = TRUE;
- }
- else
- {
- cb->state = NN_RDY;
- cb->stage = NN_QUIT /* NN_SELG */;
- cwprintf(NULL, "\r\nNNTP - Fetched %d IDs (%d bytes at %dcps)\r\n",
- cb->ids_count, cb->ids_spd.count, spdstat_end(&cb->ids_spd) );
- cwprintf(NULL, " Fetched %d Articles (%d bytes at %dcps)\r\n",
- cb->art_count, cb->art_spd.count, spdstat_end(&cb->art_spd) );
- cwprintf(NULL, " Skipped %d duplicates.\r\n", cb->ids_count-cb->art_count);
-
- ret = FALSE;
- }
- break;
-
- case NN_GETN:
- if (nntp_getnews(cb, "New"))
- {
- cb->state = NN_CMD;
- ret = TRUE;
- }
- else
- {
- cb->state = NN_RDY;
- cb->stage = NN_NEWN;
- ret = FALSE;
- }
- break;
-
- case NN_SELG:
- if (nntp_select(cb))
- {
- cb->state = NN_CMD;
- ret = TRUE;
- }
- else
- {
- cb->state = NN_RDY;
- cb->stage = NN_QUIT;
- ret = FALSE;
- }
- break;
-
- default:
- quit(cb, TRUE);
- ret = TRUE;
- break;
- }
- return(ret);
- }
-
- static void save_news(register struct nntpservers *cb)
- {
- if (direct)
- {
- FILE *out;
- long item_len;
- #ifdef OPEN_EVERY
- char buffer[256];
-
- sprintf(buffer, "<Mail$Dir>.Folder.%sNews", cb->abbr);
- out = fopen(buffer, "r+");
- fseek(out, 0, SEEK_END);
- #else
- out = cb->newsfile;
- #endif
- item_len = ftell(out);
- fseek(out, cb->rnewspos, SEEK_SET);
- fprintf(out, "#! rnews %07ld\n", item_len - cb->rnewspos - 17L);
- fseek(out, 0, SEEK_END);
- #ifdef OPEN_EVERY
- fclose(out);
- #endif
- }
- else
- {
- char line[NNTPMAXLEN + 1], buffer[256];
- FILE *temp, *out;
- long item_len;
-
- sprintf(buffer, "<Mail$Dir>.Folder.%sNews", cb->abbr);
- temp = fopen(cb->temp, "r");
- fseek(temp, 0, SEEK_END);
- if (item_len = ftell(temp), item_len > 0)
- {
- #ifdef OPEN_EVERY
- out = fopen(buffer, "a");
- #else
- if(cb->newsfile==NULL)
- cb->newsfile = fopen(buffer, "a");
- out = cb->newsfile;
- #endif
- fprintf(out, "#! rnews %d\n", (int) item_len);
- fseek(temp, 0, SEEK_SET);
- while (fgets(line, NNTPMAXLEN, temp))
- fputs(line, out);
- #ifdef OPEN_EVERY
- fclose(out);
- #endif
- }
- fclose(temp);
- remove(cb->temp);
- free(cb->temp);
- cb->temp = NULL;
- }
- if (cb->batch > 0)
- {
- (cb->batch)--;
- }
- cb->art_count++;
- spdstat_restart(&cb->art_spd);
- }
-
- static void nntp_post(register struct nntpservers *cb)
- {
- char buffer[256], line[1024];
- FILE *temp;
-
- if (nntptrace > 1)
- cwprintf(cb->window, "NNTP - sending article %s\r\n", cb->topost->name );
- sprintf( buffer, "%s.articles.%s", newsqueue, cb->topost->name );
- if (temp = fopen(buffer, "r"), temp == NULL)
- {
- if (nntptrace > 1)
- {
- cwprintf(cb->window, "NNTP - strange, article file rejects to be opened\r\n" );
- log_event(cb->tcb,"NNTP %s:%s - Cant open\n",cb->abbr,cb->topost->name);
- }
- sendit(cb, ".\r\n");
- return;
- }
- while (fgets(line, 1020, temp))
- {
- rip(line);
- if (line[0] == '.')
- sendit(cb, ".");
- sendit(cb, "%s\r\n", line);
- }
- sendit(cb, ".\r\n");
- fclose(temp);
- remove(buffer);
- }
-
- void nntp_transaction(register struct nntpservers *cb)
- {
- if (nntptrace > 4)
- cwprintf(cb->window, "nntp_transaction() enter state=%u stage=%u\r\n", cb->state, cb->stage);
- if (nntptrace > 3)
- {
- cwprintf(cb->window, "%s\r\n",cb->buf);
- }
- if (cb->state == NN_DAT)
- {
- tcp_output(cb->tcb); /* Send ACK; disk I/O is slow */
-
- if (cb->cntovr==0 && cb->buf[0] == '.' && cb->buf[1] == '\n' && cb->buf[2] == '\0')
- {
- cb->state = NN_RDY;
- if (cb->output != NULL)
- {
- fclose(cb->output);
- cb->output = NULL;
- }
- switch(cb->stage)
- {
- case NN_NEWG:
- cb->stage = NN_NEWN;
- break;
-
- case NN_NEWN:
- cb->stage = NN_GETN;
- cb->batch = 0;
- break;
-
- case NN_GETN:
- case NN_GNUM:
- save_news(cb);
- break;
-
- case NN_SELG:
- cb->stage = NN_SELG;
- break;
- }
- }
- else
- {
- BOOL dots;
- FILE *out;
-
- /* Append to data file */
- dots = (strncmp(cb->buf, "..", 2) == 0);
- if(direct && ((cb->stage==NN_GETN) || (cb->stage==NN_GNUM)))
- out = cb->newsfile;
- else
- out = cb->output;
- if (cb->stage==NN_NEWN)
- cb->ids_count++;
-
- if (out != NULL)
- {
- if (fprintf(out, "%s", cb->buf+dots) < 0)
- {
- cb->state = NN_RDY;
- tprintf(cb->tcb, "File write error\n");
- }
- }
- }
- }
- if (cb->state == NN_CMD)
- {
- char buffer[256];
- struct directory *next;
-
- if (nntptrace > 2)
- cwprintf(cb->window, "%s\n", cb->buf);
-
- switch(cb->stage)
- {
- case NN_OPEN:
- switch(atoi(cb->buf))
- {
- case 200:
- sprintf(buffer, "%s.articles", newsqueue);
- if (cb->topost = make_dir(buffer), cb->topost != NULL)
- cb->stage = NN_POST;
- else
- cb->stage = NN_NEWG;
- cb->state = NN_RDY;
- break;
-
- case 201:
- cb->stage = NN_NEWG;
- cb->state = NN_RDY;
- break;
-
- default:
- cb->stage = NN_QUIT;
- cb->state = NN_RDY;
- break;
- }
- break;
-
- case NN_POST:
- switch(atoi(cb->buf))
- {
- case 240:
- log_event(cb->tcb,"NNTP %s:%s Posted OK\n",cb->abbr,cb->topost->name);
-
- sprintf(buffer, "%s.badmarker.%s", newsqueue, cb->topost->name);
- remove(buffer);
-
- next = cb->topost->next;
- free(cb->topost->name);
- free(cb->topost);
- cb->topost = next;
- if (cb->topost != NULL)
- cb->stage = NN_POST;
- else
- cb->stage = NN_NEWG;
- cb->state = NN_RDY;
- break;
-
- case 340:
- nntp_post(cb);
- cb->stage = NN_POST;
- cb->state = NN_CMD;
- break;
-
- default:
- log_event(cb->tcb,"NNTP %s:%s Error: %s\n",cb->abbr,cb->topost->name,cb->buf);
-
- kill_dir(cb->topost);
- cb->stage = NN_NEWG;
- cb->state = NN_RDY;
- break;
- }
- break;
-
- case NN_NEWG:
- switch(atoi(cb->buf))
- {
- case 231:
- if (cb->output)
- fclose(cb->output);
- sprintf(buffer, "<Mail$Dir>.Folder.%sNG", cb->abbr);
- if (cb->output = fopen(buffer, "a"), cb->output != NULL)
- {
- cb->stage = NN_NEWG;
- cb->state = NN_DAT;
- }
- else
- {
- cb->stage = NN_NEWN;
- cb->state = NN_RDY;
- }
- break;
-
- default:
- cb->stage = NN_NEWN;
- cb->state = NN_RDY;
- break;
- }
- break;
-
- case NN_NEWN:
- switch(atoi(cb->buf))
- {
- case 230:
- if (cb->output)
- fclose(cb->output);
- sprintf(buffer, "<NNTP$Dir>.%sNew", cb->abbr);
- if (cb->output = fopen(buffer, "w"), cb->output != NULL)
- {
- cb->stage = NN_NEWN;
- cb->state = NN_DAT;
- spdstat_restart(&cb->ids_spd);
-
-
- }
- else
- {
- cb->stage = NN_BYNUM;
- cb->state = NN_RDY;
- }
- break;
- }
- break;
-
- case NN_GETN:
- case NN_GNUM:
- switch(atoi(cb->buf))
- {
- case 220:
- #ifdef OPEN_EVERY
- if (cb->newsfile)
- fclose(cb->newsfile);
- #endif
- if (cb->temp)
- {
- free(cb->temp);
- cb->temp = NULL;
- }
- if (direct)
- {
- char buffer[256];
-
- sprintf(buffer, "<Mail$Dir>.Folder.%sNews", cb->abbr);
- #ifdef OPEN_EVERY
- cb->newsfile = fopen(buffer, "a");
- #else
- if(cb->newsfile==NULL)
- cb->newsfile = fopen(buffer, "a");
- #endif
- if (cb->newsfile != NULL)
- {
- cb->state = NN_DAT;
- spdstat_restart(&cb->art_spd);
- #ifdef OPEN_EVERY
- fseek(cb->newsfile, 0, SEEK_END);
- #endif
- cb->rnewspos = ftell(cb->newsfile);
- fprintf(cb->newsfile, "#! rnews %07d\n", 0);
- }
- else
- {
- cb->state = NN_RDY;
- cb->batch--;
- }
- }
- else
- {
- cb->temp = strdup(tmpnam(NULL));
- if (cb->output = fopen(cb->temp, "w"), cb->output != NULL)
- {
- cb->state = NN_DAT;
- spdstat_restart(&cb->art_spd);
- }
- else
- {
- cb->state = NN_RDY;
- cb->batch--;
- }
- }
- break;
-
- case 430:
- case 423:
- cb->state = NN_RDY;
- cb->batch--;
- break;
-
- default:
- if (cb->stage == NN_GETN)
- cb->stage = NN_SELG;
- else
- cb->stage = NN_QUIT;
- cb->state = NN_RDY;
- break;
- }
- break;
-
- case NN_SELG:
- switch(atoi(cb->buf))
- {
- case 211:
- cb->stage = NN_SELG;
- cb->state = NN_RDY;
- break;
-
- default:
- cb->stage = NN_SELG;
- cb->state = NN_RDY;
- break;
- }
- break;
- }
- }
- if (cb->state == NN_RDY)
- {
- while (!nntp_next_command(cb))
- ;
- }
- }
-
- static void close_down(struct nntpservers *cb, BOOL normal)
- {
- if (cb->input1 != NULL)
- fclose(cb->input1);
- if (cb->input0 != NULL)
- fclose(cb->input0);
- if (cb->output != NULL)
- fclose(cb->output);
- if (cb->newsfile != NULL)
- fclose(cb->newsfile);
- if (cb->id_file != NULL)
- history_close(cb);
-
- if (cb->temp != NULL)
- {
- /* remove(cb->temp); */
- free(cb->temp);
- cb->temp = NULL;
- }
-
- cb->input1 = NULL;
- cb->input0 = NULL;
- cb->output = NULL;
- cb->newsfile= NULL;
-
- if (cb->window)
- {
- cb->window->Attr = ATTR_REVERSE;
- cb->window->Flags.flags.dont_destroy = FALSE;
- if (normal)
- Window_Close(cb->window);
- else
- cwprintf(cb->window, "\nThis session has finished, please close the window\n");
- cb->window = NULL;
- }
- start_timer(&cb->nntpcli_t);
- }
-
- /* close down link after a failure */
- static void quit(struct nntpservers *cb, BOOL normal)
- {
- cb->state = NN_RDY;
- sendit(cb, quitcmd); /* issue a quit command */
- close_tcp(cb->tcb); /* close up connection */
-
- if (nntptrace)
- {
- cwprintf(cb->window, "NNTP Closing down (%s)\r\n", normal ? "Normal" : "Error");
- if (!normal && cb->buf && cb->buf[0])
- cwprintf(cb->window, "NNTP Error - %s\r\n", cb->buf);
- }
- close_down(cb, normal);
-
- }
-
- /* nntp receiver upcall routine. fires up the state machine to parse input */
- static void nntp_rec(struct tcb *tcb, int16 cnt)
- {
- register struct nntpservers *cb;
- char c;
- struct mbuf *bp;
- int showspd = 0;
- int s;
-
- if ((cb = (struct nntpservers *) tcb->user) == NULL) /* point to our struct */
- {
- close_tcp(tcb);
- return;
- }
-
- if (nntptrace > 4)
- cwprintf(cb->window, "nntp_rec called\r\n");
-
- recv_tcp(tcb, &bp, cnt); /* suck up chars from low level routine */
-
- if (cb->state==NN_DAT)
- {
- if (cb->stage==NN_GETN)
- {
- showspd = 1;
- s = spdstat_update(&cb->art_spd, cnt);
- }
- else if (cb->stage==NN_NEWN)
- {
- showspd = 2;
- s = spdstat_update(&cb->ids_spd, cnt);
- }
- }
-
- /* Assemble input line in buffer, return if incomplete */
- while(pullone(&bp,&c) == 1)
- {
- switch(c)
- {
- case '\r': /* strip cr's */
- continue;
- case '\n': /* line is finished, go do it! */
- cb->buf[cb->cnt++] = '\n';
- cb->buf[cb->cnt] = '\0';
- nntp_transaction(cb);
- cb->cnt = 0;
- cb->cntovr = 0;
- break;
- default: /* other chars get added to buffer */
- cb->buf[cb->cnt++] = c;
- if(cb->cnt > (NNTPMAXLEN-2))
- {
- cb->buf[cb->cnt] = '\0';
- nntp_transaction(cb);
- cb->cntovr += 1;
- cb->cnt = 0;
- }
- break;
- }
- }
-
- if (cb->window && showspd == 1)
- cwprintf(cb->window, "Fetched %d Articles (%d bytes at %dcps) \r", cb->art_count, cb->art_spd.count, s );
- else if (cb->window && showspd == 2)
- cwprintf(cb->window, "Fetched %d IDs (%d bytes at %dcps) \r", cb->ids_count, cb->ids_spd.count, s );
- }
-
- /* nntp transmitter ready upcall routine. twiddles cts flag */
- static void nntp_cts(struct tcb *tcb, int16 cnt)
- {
- register struct nntpservers *cb;
-
- cb = (struct nntpservers *)tcb->user; /* point to our struct */
- if (nntptrace > 4)
- {
- cwprintf(cb->window, "nntp_cts called avail %d\r\n", cnt);
- }
-
- /* don't do anything until/unless we're supposed to be sending */
- if(cb->cts == 0)
- return;
- }
-
- /* nntp state change upcall routine. */
- static void nntp_state(register struct tcb *tcb, char old, char new)
- {
- register struct nntpservers *cb;
- extern char *tcpstates[];
-
- old = old;
-
- cb = (struct nntpservers *)tcb->user;
- if (nntptrace > 4)
- cwprintf(cb->window, "nntp_state called: %s\r\n",tcpstates[new]);
-
- switch(new)
- {
- case ESTABLISHED:
- cb->state = NN_CMD;
- cb->stage = NN_OPEN;
- cb->cnt = 0;
- cb->cntovr = 0;
- break;
-
- case CLOSE_WAIT:
- close_tcp(tcb); /* shut things down */
- break;
-
- case CLOSED:
- /* if this close was not done by us ie. a RST */
- cwprintf(cb->window, "NNTP Closed\r\n");
- close_down(cb, FALSE);
- del_tcp(tcb);
- cb->state = NN_CMD;
- cb->stage = NN_OPEN;
- break;
- }
- }
-
- /* Send message back to server */
- static void sendit(struct nntpservers *cb, char *fmt, ...)
- {
- va_list argptr;
- struct mbuf *bp;
- char tmpstring[NNTPMAXLEN+2];
-
- va_start(argptr,fmt);
- vsprintf(tmpstring,fmt,argptr);
- va_end(argptr);
-
- if (nntptrace > 3)
- {
- cwprintf(cb->window, ">>> %s\r\n", tmpstring);
- }
- bp = qdata(tmpstring, strlen(tmpstring));
- send_tcp(cb->tcb, bp);
- }
-
- static int dolists(int argc, char *argv[])
- {
- struct nntpservers *np;
-
- for (np = Nntpservers; np != NULLNNTP; np = np->next)
- {
- char tbuf[80];
-
- if (np->lowtime != -1 && np->hightime != -1)
- sprintf(tbuf, " -- %02d:%02d-%02d:%02d", np->lowtime/100, np->lowtime%100, np->hightime/100, np->hightime%100);
- else
- tbuf[0] = '\0';
- cwprintf(NULL, "%-32s (%lu/%lu%s)\r\n", np->name,
- read_timer(&np->nntpcli_t) /1000L,
- dur_timer(&np->nntpcli_t) /1000L,
- tbuf);
- }
- return 0;
- }
-
-
- static int check_files(char *abbr)
- {
- char buf[32];
-
- FILE *fp = NULL;
-
- sprintf(buf, "<NNTP$Dir>.%sGroup", abbr);
- if (fp = fopen(buf, "r"), fp!=NULL)
- fclose(fp);
- else
- return FALSE;
-
- sprintf(buf, "<NNTP$Dir>.%sHist", abbr);
- if (fp = fopen(buf, "r"), fp!=NULL)
- fclose(fp);
- else
- {
- if (fp = fopen(buf, "w"), fp!=NULL)
- {
- fprintf(fp, "# size 0\n");
- fclose(fp);
- }
- }
-
- sprintf(buf, "<NNTP$Dir>.%sLast", abbr);
- if (fp = fopen(buf, "r"), fp!=NULL)
- fclose(fp);
- else
- {
- if (fp = fopen(buf, "w"), fp!=NULL)
- {
- time_ntoa(buf, time_readgmt()-(24*60*60));
- fprintf(fp, "%s\n", buf);
- fclose(fp);
- }
- }
- return TRUE;
- }
-
-
- static int history_init(struct nntpservers *cb)
- {
- char histfile[32];
- static int atexit_registered = 0;
-
- if (!atexit_registered)
- {
- atexit(nntp_shutdown);
- atexit_registered = 1;
- }
-
- if (cb->history!=NULL)
- return (cb->history!=NULL);
-
- visdelay_begin();
-
- sprintf(histfile, "<NNTP$Dir>.%sHist", cb->abbr);
-
- if (cb->history = idhist_load(histfile /*, trim_age */), cb->history==NULL)
- {
- visdelay_end();
- return (cb->history!=NULL);
- }
- visdelay_end();
-
- cwprintf(NULL, "NNTP - %d IDs loaded\r\n", idhist_numids(cb->history));
-
- return (cb->history!=NULL);
- }
-
- /*
- * Add the id to the store, checking if we allready had it
- *
- * Dont butcher it!
- *
- * Return TRUE if allready have the ID, else FALSE
- *
- */
- static BOOL have_we(char *line, struct nntpservers *cb)
- {
- char *p;
- char buf[256];
-
- strcpy(buf, line);
-
- if (idhist_addid(cb->history, p = idhist_trimstr(buf), cb->thisfeed)<0)
- {
- if (nntptrace > 2)
- cwprintf(cb->window, "NNTP - Already got %s\r\n", line);
- return(TRUE);
- }
- else
- {
- cb->histsaved = 0;
- if (cb->id_file!=NULL)
- fprintf(cb->id_file, "%s\n", p);
- }
- return(FALSE);
- }
-
- /*
- * Extract ID History from a a ReaderS Mail file.
- * abbr is the server abbreviation.
- * Returns number of IDs read.
- */
- static int ReaderS_Hist(struct nntpservers *cb)
- {
- int n;
- long len;
- char buf[256];
- message_data temp;
- FILE *fp;
-
- sprintf(buf, "<ReadBack$Dir>.%sMail", cb->abbr);
-
- if (fp = fopen(buf, "r"), fp==NULL)
- return 0;
-
- fseek(fp, 0, SEEK_END);
- len = ftell(fp);
- fseek(fp, 9, SEEK_SET);
-
- visdelay_begin();
-
- /*
- * This is based upon the ReaderS related parts of
- * the original make_got_table() function.
- */
- for (n=0; ftell(fp) < len; n++)
- {
- /*
- * Hopefully this should provide protection from
- * broken ReaderS files
- */
- if (fread(&temp, sizeof(message_data), 1, fp)<sizeof(message_data))
- break;
- if (fgets(buf, 250, fp)==NULL)
- break;
- if (fgets(buf, 250, fp)==NULL)
- break;
-
- rip(buf);
-
- /* ReaderS ID are added with zero time stamp
- * so that they get filtered out when the History
- * file is saved
- */
- idhist_addid(cb->history, idhist_trimstr(buf), 0);
-
- fseek(fp, temp.comp_bytes + 4L, SEEK_CUR);
- }
-
- fclose(fp);
-
- visdelay_end();
-
- return n;
- }
-
- /*
- * Fill a buffer with group names from a groups file
- * Each group in the file is separated by a newline or comma
- */
- static int fillgroupbuf(FILE *fp, char *buf, int len)
- {
- int n;
- long pos;
- char *p;
- char *bufp = buf;
- char line[512];
- int lastwaswild = 0;
- long filenonwild = ftell(fp);
- char *lastnonwild = buf;
-
- while (pos = ftell(fp), fgets(line, 512, fp)!=NULL)
- {
- /*
- * Ignore blank and other dodgy lines
- */
- if (*line=='#' || *line==' ' || *line=='\n')
- continue;
-
- n = strlen(line);
- if (n>0 && line[n-1]!='\n')
- {
- if (p = strrchr(line, ','), p!=NULL)
- *p = '\0';
- if (lastwaswild)
- fseek(fp, filenonwild, SEEK_SET);
- else
- fseek(fp, 1+strlen(line)-n, SEEK_CUR);
- }
-
- p = strtok(line, ",\n");
-
- while (p && *p!='\t' && *p!=' ')
- {
- if (!strpbrk(p, "*!"))
- {
- lastnonwild = bufp;
- filenonwild = pos+(p-line);
- lastwaswild = 0;
- }
- else
- lastwaswild = 1;
-
- if (n = strlen(p), n<(len-(bufp!=buf)) )
- {
- n = sprintf(bufp, "%s%s", (bufp==buf)?"":",", p);
- len -= n;
- bufp += n;
- if (!lastwaswild)
- {
- lastnonwild += n;
- filenonwild += n;
- }
- }
- else
- {
- if (lastwaswild && lastnonwild!=buf)
- {
- *lastnonwild = '\0';
- bufp = lastnonwild;
- fseek(fp, filenonwild, SEEK_SET);
- }
- else
- fseek(fp, pos+(p-line), SEEK_SET);
- return bufp-buf;
- }
- p = strtok(NULL, ",\n");
- }
- }
- return bufp-buf;
- }
-
- /*
- * Update stats. Returns smoothed speed
- */
- int spdstat_update(spdstat_str *sp, int count)
- {
- int s, d;
- int t = alarm_timenow();
-
- sp->count += count;
-
- d = alarm_timedifference(sp->start_t, t);
- if (!d)
- d = 1;
-
- sp->last_t = t;
-
- return sp->count*100/d;
- }
-
- /*
- * Initialise stats
- */
- void spdstat_start(spdstat_str *sp)
- {
- sp->start_t = alarm_timenow();
- sp->last_t = sp->start_t;
- sp->count = 0;
- }
-
- /*
- * Account for the duration of a pause
- */
- void spdstat_restart(spdstat_str *sp)
- {
- int t = alarm_timenow();
- sp->start_t += alarm_timedifference(sp->last_t,t);
- sp->last_t = t;
- }
-
- /*
- * End timing - returns average speed
- */
- int spdstat_end(spdstat_str *sp)
- {
- int d = alarm_timedifference(sp->start_t, sp->last_t);
- if (!d)
- d = 1;
- return sp->count*100/d;
- }
-
- static int history_open(struct nntpservers *cb)
- {
- char histfile[32];
-
- sprintf(histfile, "<NNTP$Dir>.%sHist", cb->abbr);
-
- if (cb->id_file!=NULL)
- fclose(cb->id_file);
-
- /*
- * Part of backup
- */
- if (cb->id_file = fopen(histfile, "a"), cb->id_file!=NULL)
- {
- fprintf(cb->id_file, "# not trimmed\n");
- time_ntoa(histfile, cb->thisfeed);
- fprintf(cb->id_file, "# time %s\n", histfile);
- }
- return (cb->id_file!=NULL);
- }
-
- static int history_close(struct nntpservers *cb)
- {
- int a;
- char histfile[32];
- char tempfile[L_tmpnam];
-
- tmpnam(tempfile);
- sprintf(histfile, "<NNTP$Dir>.%sHist", cb->abbr);
-
- if (cb->id_file!=NULL)
- fclose(cb->id_file);
-
- cb->id_file = NULL;
-
- /*
- * The save operation does the trimming, so if the save
- * fails, the worst that can happen is that the ID file
- * doesn't get trimmed. (excepting HD dying on you...)
- */
- visdelay_begin();
-
- rename(histfile, tempfile);
-
- if (a = idhist_save(cb->history, histfile, trim_age), a!=0)
- {
- cb->histsaved = 1;
- remove(tempfile);
- }
- else
- rename(tempfile, histfile);
-
- visdelay_end();
-
- return a;
- }
-
- static void nntp_shutdown(void)
- {
- struct nntpservers *np;
-
- for(np = Nntpservers; np != NULLNNTP; np = np->next)
- {
- if (!np->histsaved)
- history_close(np);
- }
- }
-