home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / hamradio / s920603.zip / NNTPCLI.C < prev    next >
C/C++ Source or Header  |  1992-05-19  |  20KB  |  739 lines

  1. /*
  2.  *    Client routines for Network News Tranfer Protocol ala RFC977
  3.  *
  4.  *    Copyright 1990 Anders Klemets - SM0RGV, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *
  8.  *    Changes copyright 1990 Bernie Roehl, All Rights Reserved.
  9.  *    Permission granted for non-commercial copying and use, provided
  10.  *    this notice is retained.
  11.  *
  12.  *  Revision history:
  13.  *
  14.  *     May 11, 1990 - br checked for invalid chars in news filenames
  15.  *
  16.  *     May 10, 1990 - br changed date stamp in 'From ' lines to
  17.  *            seconds since GMT (to make parsing and expiry easier)
  18.  *
  19.  *     May 9, 1990 - br added locking of nntp.dat and history files,
  20.  *            second parameter to NNTP DIR, fixed bug in updating of
  21.  *            nntp.dat
  22.  *
  23.  *     early May, 1990 -- br added NNTP TRACE, NNTP DIR,
  24.  *            server-specific newsgroups and connection windows,
  25.  *            locking of newsgroup files using mlock() and rmlock(),
  26.  *            date stamping of 'From ' lines, increased stack space,
  27.  *            updating of nntp.dat only on successful sessions.
  28.  *
  29.  *     July 19, 1990 pa0gri Delinted and cleaned up. (calls and includes)
  30.  *
  31.  */
  32. #include <stdio.h>
  33. #include <sys/types.h>
  34. #include <time.h>
  35. #include <sys/timeb.h>
  36. #include <ctype.h>
  37. #include <string.h>  /* for strchr() */
  38. #ifdef    __TURBOC__
  39. #include <dir.h>
  40. #endif
  41. #include "global.h"
  42. #include "timer.h"
  43. #include "cmdparse.h"
  44. #include "commands.h"
  45. #include "socket.h"
  46. #include "usock.h"
  47. #include "netuser.h"
  48. #include "proc.h"
  49. #include "smtp.h"
  50. #include "files.h"
  51.  
  52. #define NNTPMAXLEN    512
  53.  
  54. static struct nntpservers {
  55.     struct timer nntpcli_t;
  56.     char *name;
  57.     char *groups;
  58.     int lowtime, hightime;  /* for connect window */
  59.     struct nntpservers *next;
  60. };
  61.  
  62. #define    NULLNNTP    (struct nntpservers *)NULL
  63.  
  64. #define MAXGROUPDIRS 10
  65.  
  66. static struct grouploc {
  67.     char *prefix;        /* e.g. comp, rec, net, talk, alt ... */
  68.     char *directory;     /* directory where these groups should be */
  69.     } groupdirs[MAXGROUPDIRS] = { NULL, NULL };
  70.  
  71. struct nntpservers *Nntpservers = NULLNNTP;
  72. static char *Nntpgroups = NULLCHAR;
  73. static unsigned short nntptrace = 1;
  74.  
  75. static char *validchars = "abcdefghijklmnopqrstuvwxyz0123456789-_";
  76.  
  77. static void nntptick __ARGS((void *tp));
  78. static void nntp_job __ARGS((int i1,void *tp,void *v1));
  79. static int gettxt __ARGS((FILE *network,FILE *fp));
  80. static int getreply __ARGS((FILE *network));
  81. static int getarticle __ARGS((FILE *network,char *msgid));
  82. static int dogroups __ARGS((int argc,char *argv[],void *p));
  83. static int doadds __ARGS((int argc,char *argv[],void *p));
  84. static int dodrops __ARGS((int argc,char *argv[],void *p));
  85. static int dokicks __ARGS((int argc,char *argv[],void *p));
  86. static int dolists __ARGS((int argc,char *argv[],void *p));
  87. static int donntrace __ARGS((int argc,char *argv[],void *p));
  88. static int dondir __ARGS((int argc,char *argv[],void *p));
  89.  
  90. /* Tracing levels:
  91.     0 - no tracing
  92.     1 - serious errors reported
  93.     2 - transient errors reported
  94.     3 - session progress reported
  95.     4 - actual received articles displayed
  96.  */
  97.  
  98. static struct cmds Nntpcmds[] = {
  99.     "addserver",    doadds,    0,    3,
  100.     "nntp addserver <nntpserver> <interval>",
  101.     "directory",    dondir,    0,    0,    NULLCHAR,
  102.     "dropserver",    dodrops,    0,    2,
  103.     "nntp dropserver <nntpserver>",
  104.     "groups",    dogroups,    0,    0,    NULLCHAR,
  105.     "kick",        dokicks,    0,    2,
  106.     "nntp kick <nntpserver>",
  107.     "listservers",    dolists,    0,    0,    NULLCHAR,
  108.     "trace",    donntrace,    0,    0,    NULLCHAR,
  109.     NULLCHAR,
  110. };
  111.  
  112. int
  113. donntp(argc,argv,p)
  114. int argc;
  115. char *argv[];
  116. void *p;
  117. {
  118.     return subcmd(Nntpcmds,argc,argv,p);
  119. }
  120.  
  121. static int
  122. doadds(argc,argv,p)
  123. int argc;
  124. char *argv[];
  125. void *p;
  126. {
  127.     struct nntpservers *np;
  128.     for(np = Nntpservers; np != NULLNNTP; np = np->next)
  129.         if(stricmp(np->name,argv[1]) == 0)
  130.             break;
  131.     if (np == NULLNNTP) {
  132.         np = (struct nntpservers *) callocw(1,sizeof(struct nntpservers));
  133.         np->name = strdup(argv[1]);
  134.         np->next = Nntpservers;
  135.         Nntpservers = np;
  136.         np->groups = NULLCHAR;
  137.         np->lowtime = np->hightime = -1;
  138.         np->nntpcli_t.func = nntptick;    /* what to call on timeout */
  139.         np->nntpcli_t.arg = (void *)np;
  140.     }
  141.     if (argc > 3) {
  142.         int i;
  143.         if (np->groups == NULLCHAR) {
  144.             np->groups = mallocw(NNTPMAXLEN);
  145.             *np->groups = '\0';
  146.         }
  147.         for (i = 3; i < argc; ++i) {
  148.             if (isdigit(*argv[i])) {
  149.                 int lh, ll, hh, hl;
  150.                 sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
  151.                 np->lowtime = lh * 100 + ll;
  152.                 np->hightime = hh * 100 + hl;
  153.             } else if ((strlen(np->groups)+strlen(argv[i])+2) >= NNTPMAXLEN)
  154.                 printf("Group list too long!  Group '%s' ignored!\n", argv[i]);
  155.             else {  /* it's a group, and it fits... add it to list */
  156.                 if (*np->groups != '\0')
  157.                     strcat(np->groups, ",");
  158.                 strcat(np->groups, argv[i]);
  159.             }
  160.         }
  161.         if (*np->groups == '\0') {    /* No groups specified? */
  162.             free(np->groups);
  163.             np->groups = NULLCHAR;
  164.         }
  165.     }
  166.     /* set timer duration */
  167.     set_timer(&np->nntpcli_t,atol(argv[2])*1000L);
  168.     start_timer(&np->nntpcli_t);        /* and fire it up */
  169.     return 0;
  170. }
  171.  
  172. static int
  173. dodrops(argc,argv,p)
  174. int argc;
  175. char *argv[];
  176. void *p;
  177. {
  178.     struct nntpservers *np, *npprev = NULLNNTP;
  179.     for(np = Nntpservers; np != NULLNNTP; npprev = np, np = np->next)
  180.         if(stricmp(np->name,argv[1]) == 0) {
  181.             stop_timer(&np->nntpcli_t);
  182.             free(np->name);
  183.             if (np->groups)
  184.                 free(np->groups);
  185.             if(npprev != NULLNNTP)
  186.                 npprev->next = np->next;
  187.             else
  188.                 Nntpservers = np->next;
  189.             free((char *)np);
  190.             return 0;
  191.     }
  192.     printf("No such server enabled.\n");
  193.     return 0;
  194. }
  195.  
  196. static int
  197. dolists(argc,argv,p)
  198. int argc;
  199. char *argv[];
  200. void *p;
  201. {
  202.     struct nntpservers *np;
  203.     for(np = Nntpservers; np != NULLNNTP; np = np->next) {
  204.         char tbuf[80];
  205.         if (np->lowtime != -1 && np->hightime != -1)
  206.             sprintf(tbuf, " -- %02d:%02d-%02d:%02d", np->lowtime/100, np->lowtime%100, np->hightime/100, np->hightime%100);
  207.         else
  208.             tbuf[0] = '\0';
  209.         printf("%-32s (%lu/%lu%s) %s\n", np->name,
  210.             read_timer(&np->nntpcli_t) /1000L,
  211.             dur_timer(&np->nntpcli_t) /1000L,
  212.             tbuf, np->groups ? np->groups : "");
  213.     }
  214.     return 0;
  215. }
  216.  
  217. static int donntrace(argc, argv, p)
  218. int argc;
  219. char *argv[];
  220. void *p;
  221. {
  222.     return setshort(&nntptrace,"NNTP tracing",argc,argv);
  223. }
  224.     
  225. static char *News_spool = NULL;
  226. static int np_all = 0;  /* non-zero if Newsdir is a malloc'ed space */
  227.  
  228. static int dondir(argc, argv, p)
  229. int argc;
  230. char *argv[];
  231. void *p;
  232. {
  233.     if (argc < 2) {
  234.         int i;
  235.         printf("spool: %s\n", News_spool ? News_spool : Mailspool);
  236.         printf("control: %s\n", Newsdir);
  237.         for (i = 0; i < MAXGROUPDIRS; ++i)
  238.             if (groupdirs[i].prefix)
  239.                 printf("%-10.10s %s\n", groupdirs[i].prefix, groupdirs[i].directory);
  240.     } else {
  241.         char *p;
  242.         if ((p = strchr(argv[1], '=')) != NULLCHAR) {  /* set a groupdir */
  243.             int i;
  244.             *p++ = '\0';
  245.             for (i = 0; i < MAXGROUPDIRS; ++i)
  246.                 if (groupdirs[i].prefix)
  247.                     if (!strnicmp(groupdirs[i].prefix, argv[1], strlen(argv[1]))) {
  248.                         if (groupdirs[i].directory) {
  249.                             free(groupdirs[i].directory);
  250.                             groupdirs[i].directory = NULLCHAR;
  251.                             }
  252.                         if (*p == '\0') {
  253.                             free(groupdirs[i].prefix);
  254.                             groupdirs[i].prefix = NULLCHAR;
  255.                         } else
  256.                             groupdirs[i].directory = strdup(p);
  257.                         return 0;
  258.                     }
  259.             if (*p == '\0')  /* trashing a group that's not there */
  260.                 return 0;
  261.             for (i = 0; i < MAXGROUPDIRS; ++i){
  262.                 if (groupdirs[i].prefix == NULLCHAR) {
  263.                     groupdirs[i].prefix = strdup(argv[1]);
  264.                     if (groupdirs[i].directory) {
  265.                         free(groupdirs[i].directory);
  266.                         groupdirs[i].directory = NULL;
  267.                     }
  268.                     groupdirs[i].directory = strdup(p);
  269.                     return 0;
  270.                 }
  271.             }
  272.             printf("Directory table full\n");
  273.         }
  274.         else {  /* no '=', so just set default */
  275.             if (News_spool)
  276.                 free(News_spool);
  277.             News_spool = strdup(argv[1]);
  278.         }
  279.         if (argc > 2) {  /* they specified a newsdir as well */
  280.             if (np_all)
  281.                 free(Newsdir);
  282.             Newsdir = strdup(argv[2]);
  283.             np_all = 1;
  284.         }
  285.     }
  286.     return 0;
  287. }
  288.     
  289. static int
  290. dokicks(argc,argv,p)
  291. int argc;
  292. char *argv[];
  293. void *p;
  294. {
  295.     struct nntpservers *np;
  296.     for(np = Nntpservers; np != NULLNNTP; np = np->next)
  297.         if(stricmp(np->name,argv[1]) == 0) {
  298.             /* If the timer is not running, the timeout function has
  299.             * already been called and we don't want to call it again.
  300.             */
  301.             if(run_timer(&np->nntpcli_t)) {
  302.                 stop_timer(&np->nntpcli_t);
  303.                 nntptick((void *)np);
  304.             }
  305.             return 0;
  306.     }
  307.     printf("No such server enabled.\n");
  308.     return 0;
  309. }
  310.  
  311. static int
  312. dogroups(argc,argv,p)
  313. int argc;
  314. char *argv[];
  315. void *p;
  316. {
  317.     int i;
  318.     if(argc < 2) {
  319.         if(Nntpgroups == NULLCHAR || (Nntpgroups != NULLCHAR && strcmp(Nntpgroups,"*") == 0))
  320.             printf("All groups are currently enabled.\n");
  321.         else
  322.             printf("Currently enabled newsgroups:\n%s\n",Nntpgroups);
  323.         return 0;
  324.     }
  325.     if(Nntpgroups == NULLCHAR)
  326.         Nntpgroups = mallocw(NNTPMAXLEN);
  327.     *Nntpgroups = '\0';
  328.     for(i=1; i < argc; ++i) {
  329.         if(i > 1)
  330.             strcat(Nntpgroups,",");
  331.         strcat(Nntpgroups,argv[i]);
  332.     }
  333.     return 0;
  334. }
  335.  
  336. /* This is the routine that gets called every so often to connect to
  337.  * NNTP servers.
  338.  */
  339. static void
  340. nntptick(tp)
  341. void *tp;
  342. {
  343.     newproc("NNTP client", 3072, nntp_job, 0, tp, NULL,0);
  344. }
  345.  
  346. static void
  347. nntp_job(i1,tp,v1)
  348. int i1;
  349. void *tp, *v1;
  350. {
  351.     FILE *fp, *tmpf;
  352.     int s = -1, i;
  353.     FILE *network;
  354. /*    long pos; */
  355.     struct tm *ltm;
  356.     time_t t;
  357.     int now;
  358.     struct nntpservers *np = (struct nntpservers *) tp;
  359.     struct sockaddr_in fsocket;
  360.     char tbuf[NNTPMAXLEN], buf[NNTPMAXLEN], *cp, *lastdate = NULLCHAR;
  361.     if (nntptrace >= 3)
  362.         printf("NNTP daemon entered, target = %s\n",np->name);
  363.     if(availmem() != 0){
  364.         if (nntptrace >= 2)
  365.             printf("NNTP daemon quit -- low memory\n");
  366.         /* Memory is tight, don't do anything */
  367.         start_timer(&np->nntpcli_t);
  368.         return;
  369.     }
  370.  
  371.     time(&t);    /* more portable than gettime() */
  372.     ltm = localtime(&t);
  373.     now = ltm->tm_hour * 100 + ltm->tm_min;
  374.     if (np->lowtime < np->hightime) {  /* doesn't cross midnight */
  375.         if (now < np->lowtime || now >= np->hightime) {
  376.             if (nntptrace >= 3)
  377.                 printf("NNTP window to '%s' not open\n", np->name);
  378.             start_timer(&np->nntpcli_t);
  379.             return;
  380.         }
  381.     } else {
  382.         if (now < np->lowtime && now >= np->hightime) {
  383.             if (nntptrace >= 3)
  384.                 printf("NNTP window to '%s' not open\n", np->name);
  385.             start_timer(&np->nntpcli_t);
  386.             return;
  387.         }
  388.     }
  389.  
  390.     fsocket.sin_addr.s_addr = resolve(np->name);
  391.     if(fsocket.sin_addr.s_addr == 0) {  /* No IP address found */
  392.         if (nntptrace >= 2)
  393.             printf("NNTP can't resolve host '%s'\n", np->name);
  394.         /* Try again later */
  395.         start_timer(&np->nntpcli_t);
  396.         return;
  397.     }
  398.     fsocket.sin_family = AF_INET;
  399.     fsocket.sin_port = IPPORT_NNTP;
  400.  
  401.     s = socket(AF_INET,SOCK_STREAM,0);
  402.     if(connect(s,(char *)&fsocket,SOCKSIZE) == -1){
  403.         cp = sockerr(s);
  404.         log(s,"NNTP %s Connect failed: %s",psocket(&fsocket),
  405.             cp != NULLCHAR ? cp : "");
  406.         if (nntptrace >= 2)
  407.             printf("NNTP %s Connect failed: %s\n",psocket(&fsocket),
  408.         cp != NULLCHAR ? cp : "");
  409.         goto quit;
  410.     }
  411.     network = fdopen(s,"r+t");
  412.  
  413.     /* Eat the banner */
  414.     i = getreply(network);
  415.     if(i == -1 || i >= 400) {
  416.         log(fileno(network),"NNTP %s bad reply on banner (response was %d)",psocket(&fsocket),i);
  417.         if (nntptrace >= 1)
  418.             printf("NNTP %s bad reply on banner (response was %d)\n",psocket(&fsocket),i);
  419.         goto quit;
  420.     }
  421.  
  422.     if (mlock(Newsdir, "nntp")) {
  423.         if (nntptrace >= 2)
  424.             printf("NNTP %s Connect failed: cannot lock nntp.dat\n", psocket(&fsocket));
  425.         goto quit;
  426.     }
  427.     sprintf(buf,"%s/nntp.dat",Newsdir);
  428.     if((fp = fopen(buf,APPEND_TEXT)) == NULLFILE) {
  429.         log(fileno(network),"NNTP %s Connect failed: Cannot open %s",psocket(&fsocket),
  430.             buf);
  431.         if (nntptrace >= 1)
  432.             printf("NNTP %s Connect failed: Cannot open %s\n",psocket(&fsocket), buf);
  433.         rmlock(Newsdir, "nntp");
  434.         goto quit;
  435.     }
  436.     rewind(fp);
  437. /*    for(pos=0L; fgets(buf,NNTPMAXLEN,fp) != NULLCHAR;pos=ftell(fp)) { */
  438.     for(; fgets(buf,NNTPMAXLEN,fp) != NULLCHAR;) {
  439.         if((cp = strchr(buf,' ')) == NULLCHAR)
  440.             continue;    /* something wrong with this line, skip it */
  441.         *cp = '\0';
  442.         if(stricmp(buf,np->name) == 0) {
  443.             rip(cp+1);
  444.             lastdate = strdup(cp+1);
  445.             break;
  446.         }
  447.     }
  448.     fclose(fp);
  449.     rmlock(Newsdir, "nntp");
  450.  
  451.     if(lastdate == NULLCHAR)
  452.         lastdate = strdup("700101 000000");
  453.     /* snapshot the time for use later in re-writing nntp.dat */
  454.     time(&t);
  455.     ltm = localtime(&t);
  456.                 
  457.     /* Get a list of new message-id's */
  458.     if (np->groups) {
  459.         if (nntptrace >= 3)
  460.             printf("==>NEWNEWS %s %s\n", np->groups, lastdate);
  461.         fprintf(network,"NEWNEWS %s %s\n", np->groups, lastdate);
  462.     } else {
  463.         if (nntptrace >= 3)
  464.             printf("==>NEWNEWS %s %s\n", Nntpgroups != NULLCHAR ? Nntpgroups : "*", lastdate);
  465.         fprintf(network,"NEWNEWS %s %s\n",Nntpgroups != NULLCHAR ? Nntpgroups : "*", lastdate);
  466.     }
  467.     free(lastdate);
  468.     /* Get the response */
  469.     if((i = getreply(network)) != 230) { /* protocol error */
  470.         log(fileno(network),"NNTP %s protocol error (response was %d)",psocket(&fsocket),i);
  471.         if (nntptrace >= 1)
  472.             printf("NNTP %s protocol error (response was %d)\n",psocket(&fsocket),i);
  473.         goto quit;
  474.     }
  475.     if((tmpf = tmpfile()) == NULLFILE) {
  476.         if (nntptrace >= 1)
  477.             printf("NNTP %s Cannot open temp file\n", psocket(&fsocket));
  478.         goto quit;
  479.     }
  480.     if(gettxt(network,tmpf) == -1) {
  481.         log(fileno(network), "NNTP %s giving up: gettxt() failure",psocket(&fsocket));
  482.         if (nntptrace >= 1)
  483.             printf("NNTP %s giving up: gettxt() failure\n",psocket(&fsocket));
  484.         fclose(tmpf);
  485.         goto quit;
  486.     }
  487.  
  488.     /* Open the history file */
  489.     if (mlock(Newsdir, "history")) {
  490.         if (nntptrace >= 1)
  491.             printf("NNTP %s giving up: couldn't lock history file\n", psocket(&fsocket));
  492.         fclose(tmpf);
  493.         goto quit;
  494.     }
  495.     sprintf(buf,"%s/history",Newsdir);
  496.     if((fp = fopen(buf,APPEND_TEXT)) == NULLFILE) {
  497.         log(fileno(network),"NNTP %s Connect failed: Cannot open %s",psocket(&fsocket), buf);
  498.         if (nntptrace >= 1)
  499.             printf("NNTP %s Connect failed: Cannot open %s\n",psocket(&fsocket), buf);
  500.         fclose(tmpf);
  501.         goto quit;
  502.     }
  503.     /* search through the history file for matching message id's */
  504.     rewind(tmpf);
  505.     while(fgets(tbuf,NNTPMAXLEN,tmpf) != NULLCHAR) {
  506.         i = 0;
  507.         rewind(fp);
  508.         while(fgets(buf,NNTPMAXLEN,fp) != NULLCHAR) {
  509.             if(stricmp(buf,tbuf) == 0) {
  510.                 i = 1;
  511.                 break;
  512.             }
  513.             pwait(NULL);
  514.         }
  515.         if(i == 0) {        /* not found, get the article */
  516.             if(getarticle(network,tbuf) == -1) {
  517.                 log(fileno(network),"NNTP %s Giving up: could not get article",psocket(&fsocket));
  518.                 if (nntptrace >= 2)
  519.                     printf("NNTP %s Giving up: could not get article\n",psocket(&fsocket));
  520.                 fclose(fp);
  521.                 rmlock(Newsdir, "history");
  522.                 fclose(tmpf);
  523.                 goto quit;
  524.             }
  525.             fprintf(fp,"%s",tbuf); /* add the new message id */
  526.         }
  527.     }
  528.     fclose(fp);
  529.     rmlock(Newsdir, "history");
  530.     fclose(tmpf);
  531.     if (nntptrace >= 3)
  532.         printf("==>QUIT\n");
  533.     fprintf(network,"QUIT\n");
  534.     /* Eat the response */
  535.     getreply(network);
  536.     /* NOW, update the nntp.dat file */
  537.     if (mlock(Newsdir, "nntp")) {
  538.         if (nntptrace >= 2)
  539.             printf("NNTP %s Could not lock nntp.dat for update\n", psocket(&fsocket));
  540.         goto quit;
  541.     }
  542.     sprintf(buf,"%s/nntp.dat",Newsdir);
  543.     fp = fopen(buf,READ_TEXT);
  544.     sprintf(buf, "%s/nntp.tmp",Newsdir);
  545.     if ((tmpf = fopen(buf, WRITE_TEXT)) == NULLFILE)
  546.         if (nntptrace >= 1)
  547.             printf("NNTP %s Cannot create temp file '%s'\n", psocket(&fsocket), buf);
  548.     if (fp == NULLFILE || tmpf == NULLFILE) {
  549.         log(fileno(network),"NNTP %s Could not update %s", psocket(&fsocket), buf);
  550.         if (nntptrace >= 2)
  551.             printf("NNTP %s Could not update %s\n",psocket(&fsocket), buf);
  552.         if (fp)
  553.             fclose(fp);
  554.         if (tmpf)
  555.             fclose(tmpf);
  556.         rmlock(Newsdir, "nntp");
  557.         goto quit;
  558.     }
  559.     while (fgets(tbuf, sizeof(tbuf), fp))
  560.         if (strnicmp(tbuf, np->name, strlen(np->name)))
  561.             fputs(tbuf, tmpf);
  562.     fprintf(tmpf,"%s %02d%02d%02d %02d%02d%02d\n",np->name,ltm->tm_year%100,ltm->tm_mon+1,
  563.         ltm->tm_mday,ltm->tm_hour,ltm->tm_min,ltm->tm_sec);
  564.     fclose(fp);
  565.     fclose(tmpf);
  566.     sprintf(buf, "%s/nntp.dat", Newsdir);
  567.     sprintf(tbuf, "%s/nntp.tmp", Newsdir);
  568.     unlink(buf);
  569.     rename(tbuf, buf);
  570.     rmlock(Newsdir, "nntp");
  571. quit:
  572.     if (nntptrace >= 3)
  573.         printf("NNTP daemon exiting\n");
  574.     fclose(network);
  575.     /* Restart timer */
  576.     start_timer(&np->nntpcli_t);
  577.     return;
  578. }
  579.  
  580. static int
  581. gettxt(network,fp)
  582. FILE *network;
  583. FILE *fp;
  584. {
  585.     char buf[NNTPMAXLEN];
  586.     int nlines;
  587.     for (nlines = 0; fgets(buf,NNTPMAXLEN,network) != NULLCHAR; ++nlines) {
  588.         if (nntptrace >= 4)
  589.             printf("<==%s", buf);
  590.         if(strcmp(buf,".\n") == 0) {
  591.             if (nntptrace >= 3)
  592.                 printf("NNTP received %d lines\n", nlines);
  593.             return 0;
  594.             }
  595.         /* check for escaped '.' characters */
  596.         if(strcmp(buf,"..\n") == 0)
  597.             fputs(".\n",fp);
  598.         else
  599.             fputs(buf,fp);
  600.     }
  601.     if (nntptrace >= 1)
  602.         printf("NNTP receive error after %d lines\n", nlines);
  603.     return -1;
  604. }
  605.  
  606. static int
  607. getreply(network)
  608. FILE *network;
  609. {
  610.     char buf[NNTPMAXLEN];
  611.     int response;
  612.     while(fgets(buf,NNTPMAXLEN,network) != NULLCHAR) {
  613.         /* skip informative messages and blank lines */
  614.         if(buf[0] == '\0' || buf[0] == '1')
  615.             continue;
  616.         sscanf(buf,"%d",&response);
  617.         if (nntptrace >= 3)
  618.             printf("<==%s\n", buf);
  619.         return response;
  620.     }
  621.     if (nntptrace >= 3)
  622.         printf("==No response\n");
  623.     return -1;
  624. }
  625.  
  626. static int
  627. getarticle(network,msgid)
  628. FILE *network;
  629. char *msgid;
  630. {
  631.     char buf[NNTPMAXLEN], froml[NNTPMAXLEN], newgl[NNTPMAXLEN];
  632.     FILE *fp, *tmpf;
  633.     int r;
  634.     char *cp;
  635.     extern int Smtpquiet;
  636.  
  637.     if (nntptrace >= 3)
  638.         printf("==>ARTICLE %s", msgid);
  639.     fprintf(network,"ARTICLE %s", msgid);
  640.     r = getreply(network);
  641.     if(r == -1 || r >= 500)
  642.         return -1;
  643.     if(r >= 400)
  644.         return 0;
  645.     if((tmpf = tmpfile()) == NULLFILE) {
  646.         if (nntptrace >= 1)
  647.             printf("NNTP Cannot open temp file for article\n");
  648.         return -1;
  649.     }
  650.     if(gettxt(network,tmpf) == -1) {
  651.         fclose(tmpf);
  652.         return -1;
  653.     }
  654.     /* convert the article into mail format */
  655.     rewind(tmpf);
  656.     froml[0] = '\0';
  657.     newgl[0] = '\0';
  658.     while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
  659.         if(strncmp(buf,"From: ",6) == 0) {
  660.             struct timeb t;
  661.             ftime(&t);
  662.             rip(&buf[6]);
  663.             sprintf(froml,"From %s %ld\n",&buf[6], t.time);
  664.             if(newgl[0] != '\0')
  665.                 break;
  666.         }
  667.         if(strncmp(buf,"Newsgroups: ",12) == 0) {
  668.             strcpy(newgl,&buf[12]);
  669.             if(froml[0] != '\0')
  670.                 break;
  671.         }
  672.         /* invalid article - missing 'From:' line or 'Newsgroups:' line */
  673.         if(strcmp(buf,"\n") == 0 && (froml[0] == '\0' || newgl[0] == '\0')) {
  674. /*            fclose(fp); */
  675.             fclose(tmpf);
  676.             return 0;
  677.         }
  678.     }
  679.     sprintf(buf,"%s/",News_spool ? News_spool : Mailspool);
  680.     for(cp=newgl;;++cp) {
  681.         if(*cp == '.') {
  682. #ifdef __TURBOC__
  683.             mkdir(buf); /* create a subdirectory, if necessary */
  684. #else
  685.             mkdir(buf,0755); /* create a subdirectory, if necessary */
  686. #endif
  687.             strcat(buf,"/");
  688.             continue;
  689.         }
  690.         if(*cp == ',' || *cp == '\n') {
  691.             char tempdir[80], prefix[20], *p;
  692.             strcpy(tempdir, buf);
  693.             if ((p = strrchr(tempdir, '/')) != NULLCHAR) {
  694.                 *p++ = '\0';
  695.                 strcpy(prefix, p);
  696.             }
  697.             if (mlock(tempdir, prefix)) {
  698.                 if (nntptrace >= 2)
  699.                     printf("NNTP group '%s' is locked\n", buf);
  700.                 return -1;
  701.             }
  702.             strcat(buf,".txt");
  703.             /* open the mail file */
  704.             if (nntptrace >= 3)
  705.                 printf("Writing article to '%s'\n", buf);
  706.             if((fp = fopen(buf,APPEND_TEXT)) != NULLFILE) {
  707.                 fputs(froml,fp);
  708.                 rewind(tmpf);
  709.                 while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
  710.                     /* for UNIX mail compatiblity */
  711.                     if(strncmp(buf,"From ",5) == 0)
  712.                         putc('>',fp);
  713.                     fputs(buf,fp);
  714.                 }
  715.                 putc('\n',fp);
  716.                 fclose(fp);
  717.             }
  718.             rmlock(tempdir, prefix);
  719.             if (*cp == '\n') 
  720.                 break;
  721.             else
  722.                 sprintf(buf,"%s/",News_spool ? News_spool : Mailspool);
  723.             continue;
  724.         }
  725.         buf[strlen(buf)+1] = '\0';
  726.         buf[strlen(buf)] = strchr(validchars, tolower(*cp)) ? *cp : '_';
  727.     }
  728.     fclose(tmpf);
  729.     strcpy(buf,msgid);        /* Get a copy we can munge */
  730.     rip(buf);            /* remove trailing new-line */
  731.     rip(newgl);            /* ditto */
  732. #ifdef    notdef
  733.     printf("New news arrived: %s, article %s%c\n",newgl,buf,Smtpquiet?' ':'\007');
  734. #else
  735.     printf("New news arrived: %s, article %s\n",newgl,buf);
  736. #endif
  737.     return 0;
  738. }
  739.