home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / network / src_1218.zip / NNTPCLI.C < prev    next >
C/C++ Source or Header  |  1991-03-10  |  20KB  |  737 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((int s,FILE *fp));
  80. static int getreply __ARGS((int s));
  81. static int getarticle __ARGS((int s,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.                 tprintf("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.     tprintf("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.         tprintf("%-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.         tprintf("spool: %s\n", News_spool ? News_spool : Mailspool);
  236.         tprintf("control: %s\n", Newsdir);
  237.         for (i = 0; i < MAXGROUPDIRS; ++i)
  238.             if (groupdirs[i].prefix)
  239.                 tprintf("%-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.             tprintf("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.     tprintf("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.             tprintf("All groups are currently enabled.\n");
  321.         else
  322.             tprintf("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. /*    long pos; */
  354.     struct tm *ltm;
  355.     time_t t;
  356.     int now;
  357.     struct nntpservers *np = (struct nntpservers *) tp;
  358.     struct sockaddr_in fsocket;
  359.     char tbuf[NNTPMAXLEN], buf[NNTPMAXLEN], *cp, *lastdate = NULLCHAR;
  360.     if (nntptrace >= 3)
  361.         tprintf("NNTP daemon entered, target = %s\n",np->name);
  362.     if(availmem() < Memthresh){
  363.         if (nntptrace >= 2)
  364.             tprintf("NNTP daemon quit -- low memory\n");
  365.         /* Memory is tight, don't do anything */
  366.         start_timer(&np->nntpcli_t);
  367.         return;
  368.     }
  369.  
  370.     time(&t);    /* more portable than gettime() */
  371.     ltm = localtime(&t);
  372.     now = ltm->tm_hour * 100 + ltm->tm_min;
  373.     if (np->lowtime < np->hightime) {  /* doesn't cross midnight */
  374.         if (now < np->lowtime || now >= np->hightime) {
  375.             if (nntptrace >= 3)
  376.                 tprintf("NNTP window to '%s' not open\n", np->name);
  377.             start_timer(&np->nntpcli_t);
  378.             return;
  379.         }
  380.     } else {
  381.         if (now < np->lowtime && now >= np->hightime) {
  382.             if (nntptrace >= 3)
  383.                 tprintf("NNTP window to '%s' not open\n", np->name);
  384.             start_timer(&np->nntpcli_t);
  385.             return;
  386.         }
  387.     }
  388.  
  389.     fsocket.sin_addr.s_addr = resolve(np->name);
  390.     if(fsocket.sin_addr.s_addr == 0) {  /* No IP address found */
  391.         if (nntptrace >= 2)
  392.             tprintf("NNTP can't resolve host '%s'\n", np->name);
  393.         /* Try again later */
  394.         start_timer(&np->nntpcli_t);
  395.         return;
  396.     }
  397.     fsocket.sin_family = AF_INET;
  398.     fsocket.sin_port = IPPORT_NNTP;
  399.  
  400.     s = socket(AF_INET,SOCK_STREAM,0);
  401.     sockmode(s,SOCK_ASCII);
  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.             tprintf("NNTP %s Connect failed: %s\n",psocket(&fsocket),
  408.         cp != NULLCHAR ? cp : "");
  409.         goto quit;
  410.     }
  411.     /* Eat the banner */
  412.     i = getreply(s);
  413.     if(i == -1 || i >= 400) {
  414.         log(s,"NNTP %s bad reply on banner (response was %d)",psocket(&fsocket),i);
  415.         if (nntptrace >= 1)
  416.             tprintf("NNTP %s bad reply on banner (response was %d)\n",psocket(&fsocket),i);
  417.         goto quit;
  418.     }
  419.  
  420.     if (mlock(Newsdir, "nntp")) {
  421.         if (nntptrace >= 2)
  422.             tprintf("NNTP %s Connect failed: cannot lock nntp.dat\n", psocket(&fsocket));
  423.         goto quit;
  424.     }
  425.     sprintf(buf,"%s/nntp.dat",Newsdir);
  426.     if((fp = fopen(buf,APPEND_TEXT)) == NULLFILE) {
  427.         log(s,"NNTP %s Connect failed: Cannot open %s",psocket(&fsocket),
  428.             buf);
  429.         if (nntptrace >= 1)
  430.             tprintf("NNTP %s Connect failed: Cannot open %s\n",psocket(&fsocket), buf);
  431.         rmlock(Newsdir, "nntp");
  432.         goto quit;
  433.     }
  434.     rewind(fp);
  435. /*    for(pos=0L; fgets(buf,NNTPMAXLEN,fp) != NULLCHAR;pos=ftell(fp)) { */
  436.     for(; fgets(buf,NNTPMAXLEN,fp) != NULLCHAR;) {
  437.         if((cp = strchr(buf,' ')) == NULLCHAR)
  438.             continue;    /* something wrong with this line, skip it */
  439.         *cp = '\0';
  440.         if(stricmp(buf,np->name) == 0) {
  441.             rip(cp+1);
  442.             lastdate = strdup(cp+1);
  443.             break;
  444.         }
  445.     }
  446.     fclose(fp);
  447.     rmlock(Newsdir, "nntp");
  448.  
  449.     if(lastdate == NULLCHAR)
  450.         lastdate = strdup("700101 000000");
  451.     /* snapshot the time for use later in re-writing nntp.dat */
  452.     time(&t);
  453.     ltm = localtime(&t);
  454.                 
  455.     /* Get a list of new message-id's */
  456.     if (np->groups) {
  457.         if (nntptrace >= 3)
  458.             tprintf("==>NEWNEWS %s %s\n", np->groups, lastdate);
  459.         usprintf(s,"NEWNEWS %s %s\n", np->groups, lastdate);
  460.     } else {
  461.         if (nntptrace >= 3)
  462.             tprintf("==>NEWNEWS %s %s\n", Nntpgroups != NULLCHAR ? Nntpgroups : "*", lastdate);
  463.         usprintf(s,"NEWNEWS %s %s\n",Nntpgroups != NULLCHAR ? Nntpgroups : "*", lastdate);
  464.     }
  465.     free(lastdate);
  466.     /* Get the response */
  467.     if((i = getreply(s)) != 230) { /* protocol error */
  468.         log(s,"NNTP %s protocol error (response was %d)",psocket(&fsocket),i);
  469.         if (nntptrace >= 1)
  470.             tprintf("NNTP %s protocol error (response was %d)\n",psocket(&fsocket),i);
  471.         goto quit;
  472.     }
  473.     if((tmpf = tmpfile()) == NULLFILE) {
  474.         if (nntptrace >= 1)
  475.             tprintf("NNTP %s Cannot open temp file\n", psocket(&fsocket));
  476.         goto quit;
  477.     }
  478.     if(gettxt(s,tmpf) == -1) {
  479.         log(s, "NNTP %s giving up: gettxt() failure",psocket(&fsocket));
  480.         if (nntptrace >= 1)
  481.             tprintf("NNTP %s giving up: gettxt() failure\n",psocket(&fsocket));
  482.         fclose(tmpf);
  483.         goto quit;
  484.     }
  485.  
  486.     /* Open the history file */
  487.     if (mlock(Newsdir, "history")) {
  488.         if (nntptrace >= 1)
  489.             tprintf("NNTP %s giving up: couldn't lock history file\n", psocket(&fsocket));
  490.         fclose(tmpf);
  491.         goto quit;
  492.     }
  493.     sprintf(buf,"%s/history",Newsdir);
  494.     if((fp = fopen(buf,APPEND_TEXT)) == NULLFILE) {
  495.         log(s,"NNTP %s Connect failed: Cannot open %s",psocket(&fsocket), buf);
  496.         if (nntptrace >= 1)
  497.             tprintf("NNTP %s Connect failed: Cannot open %s\n",psocket(&fsocket), buf);
  498.         fclose(tmpf);
  499.         goto quit;
  500.     }
  501.     /* search through the history file for matching message id's */
  502.     rewind(tmpf);
  503.     while(fgets(tbuf,NNTPMAXLEN,tmpf) != NULLCHAR) {
  504.         i = 0;
  505.         rewind(fp);
  506.         while(fgets(buf,NNTPMAXLEN,fp) != NULLCHAR) {
  507.             if(stricmp(buf,tbuf) == 0) {
  508.                 i = 1;
  509.                 break;
  510.             }
  511.             pwait(NULL);
  512.         }
  513.         if(i == 0) {        /* not found, get the article */
  514.             if(getarticle(s,tbuf) == -1) {
  515.                 log(s,"NNTP %s Giving up: could not get article",psocket(&fsocket));
  516.                 if (nntptrace >= 2)
  517.                     tprintf("NNTP %s Giving up: could not get article\n",psocket(&fsocket));
  518.                 fclose(fp);
  519.                 rmlock(Newsdir, "history");
  520.                 fclose(tmpf);
  521.                 goto quit;
  522.             }
  523.             fprintf(fp,"%s",tbuf); /* add the new message id */
  524.         }
  525.     }
  526.     fclose(fp);
  527.     rmlock(Newsdir, "history");
  528.     fclose(tmpf);
  529.     if (nntptrace >= 3)
  530.         tprintf("==>QUIT\n");
  531.     usprintf(s,"QUIT\n");
  532.     /* Eat the response */
  533.     getreply(s);
  534.     /* NOW, update the nntp.dat file */
  535.     if (mlock(Newsdir, "nntp")) {
  536.         if (nntptrace >= 2)
  537.             tprintf("NNTP %s Could not lock nntp.dat for update\n", psocket(&fsocket));
  538.         goto quit;
  539.     }
  540.     sprintf(buf,"%s/nntp.dat",Newsdir);
  541.     fp = fopen(buf,READ_TEXT);
  542.     sprintf(buf, "%s/nntp.tmp",Newsdir);
  543.     if ((tmpf = fopen(buf, WRITE_TEXT)) == NULLFILE)
  544.         if (nntptrace >= 1)
  545.             tprintf("NNTP %s Cannot create temp file '%s'\n", psocket(&fsocket), buf);
  546.     if (fp == NULLFILE || tmpf == NULLFILE) {
  547.         log(s,"NNTP %s Could not update %s", psocket(&fsocket), buf);
  548.         if (nntptrace >= 2)
  549.             tprintf("NNTP %s Could not update %s\n",psocket(&fsocket), buf);
  550.         if (fp)
  551.             fclose(fp);
  552.         if (tmpf)
  553.             fclose(tmpf);
  554.         rmlock(Newsdir, "nntp");
  555.         goto quit;
  556.     }
  557.     while (fgets(tbuf, sizeof(tbuf), fp))
  558.         if (strnicmp(tbuf, np->name, strlen(np->name)))
  559.             fputs(tbuf, tmpf);
  560.     fprintf(tmpf,"%s %02d%02d%02d %02d%02d%02d\n",np->name,ltm->tm_year%100,ltm->tm_mon+1,
  561.         ltm->tm_mday,ltm->tm_hour,ltm->tm_min,ltm->tm_sec);
  562.     fclose(fp);
  563.     fclose(tmpf);
  564.     sprintf(buf, "%s/nntp.dat", Newsdir);
  565.     sprintf(tbuf, "%s/nntp.tmp", Newsdir);
  566.     unlink(buf);
  567.     rename(tbuf, buf);
  568.     rmlock(Newsdir, "nntp");
  569. quit:
  570.     if (nntptrace >= 3)
  571.         tprintf("NNTP daemon exiting\n");
  572.     close_s(s);
  573.     /* Restart timer */
  574.     start_timer(&np->nntpcli_t);
  575.     return;
  576. }
  577.  
  578. static int
  579. gettxt(s,fp)
  580. int s;
  581. FILE *fp;
  582. {
  583.     char buf[NNTPMAXLEN];
  584.     int nlines;
  585.     for (nlines = 0; recvline(s,buf,NNTPMAXLEN) != -1; ++nlines) {
  586.         if (nntptrace >= 4)
  587.             tprintf("<==%s", buf);
  588.         if(strcmp(buf,".\n") == 0) {
  589.             if (nntptrace >= 3)
  590.                 tprintf("NNTP received %d lines\n", nlines);
  591.             return 0;
  592.             }
  593.         /* check for escaped '.' characters */
  594.         if(strcmp(buf,"..\n") == 0)
  595.             fputs(".\n",fp);
  596.         else
  597.             fputs(buf,fp);
  598.     }
  599.     if (nntptrace >= 1)
  600.         tprintf("NNTP receive error after %d lines\n", nlines);
  601.     return -1;
  602. }
  603.  
  604. static int
  605. getreply(s)
  606. int s;
  607. {
  608.     char buf[NNTPMAXLEN];
  609.     int response;
  610.     while(recvline(s,buf,NNTPMAXLEN) != -1) {
  611.         /* skip informative messages and blank lines */
  612.         if(buf[0] == '\0' || buf[0] == '1')
  613.             continue;
  614.         sscanf(buf,"%d",&response);
  615.         if (nntptrace >= 3)
  616.             tprintf("<==%s\n", buf);
  617.         return response;
  618.     }
  619.     if (nntptrace >= 3)
  620.         tprintf("==No response\n");
  621.     return -1;
  622. }
  623.  
  624. static int
  625. getarticle(s,msgid)
  626. int s;
  627. char *msgid;
  628. {
  629.     char buf[NNTPMAXLEN], froml[NNTPMAXLEN], newgl[NNTPMAXLEN];
  630.     FILE *fp, *tmpf;
  631.     int r;
  632.     char *cp;
  633.     extern int Smtpquiet;
  634.  
  635.     if (nntptrace >= 3)
  636.         tprintf("==>ARTICLE %s", msgid);
  637.     usprintf(s,"ARTICLE %s", msgid);
  638.     r = getreply(s);
  639.     if(r == -1 || r >= 500)
  640.         return -1;
  641.     if(r >= 400)
  642.         return 0;
  643.     if((tmpf = tmpfile()) == NULLFILE) {
  644.         if (nntptrace >= 1)
  645.             tprintf("NNTP Cannot open temp file for article\n");
  646.         return -1;
  647.     }
  648.     if(gettxt(s,tmpf) == -1) {
  649.         fclose(tmpf);
  650.         return -1;
  651.     }
  652.     /* convert the article into mail format */
  653.     rewind(tmpf);
  654.     froml[0] = '\0';
  655.     newgl[0] = '\0';
  656.     while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
  657.         if(strncmp(buf,"From: ",6) == 0) {
  658.             struct timeb t;
  659.             ftime(&t);
  660.             rip(&buf[6]);
  661.             sprintf(froml,"From %s %ld\n",&buf[6], t.time);
  662.             if(newgl[0] != '\0')
  663.                 break;
  664.         }
  665.         if(strncmp(buf,"Newsgroups: ",12) == 0) {
  666.             strcpy(newgl,&buf[12]);
  667.             if(froml[0] != '\0')
  668.                 break;
  669.         }
  670.         /* invalid article - missing 'From:' line or 'Newsgroups:' line */
  671.         if(strcmp(buf,"\n") == 0 && (froml[0] == '\0' || newgl[0] == '\0')) {
  672. /*            fclose(fp); */
  673.             fclose(tmpf);
  674.             return 0;
  675.         }
  676.     }
  677.     sprintf(buf,"%s/",News_spool ? News_spool : Mailspool);
  678.     for(cp=newgl;;++cp) {
  679.         if(*cp == '.') {
  680. #ifdef __TURBOC__
  681.             mkdir(buf); /* create a subdirectory, if necessary */
  682. #else
  683.             mkdir(buf,0755); /* create a subdirectory, if necessary */
  684. #endif
  685.             strcat(buf,"/");
  686.             continue;
  687.         }
  688.         if(*cp == ',' || *cp == '\n') {
  689.             char tempdir[80], prefix[20], *p;
  690.             strcpy(tempdir, buf);
  691.             if ((p = strrchr(tempdir, '/')) != NULLCHAR) {
  692.                 *p++ = '\0';
  693.                 strcpy(prefix, p);
  694.             }
  695.             if (mlock(tempdir, prefix)) {
  696.                 if (nntptrace >= 2)
  697.                     tprintf("NNTP group '%s' is locked\n", buf);
  698.                 return -1;
  699.             }
  700.             strcat(buf,".txt");
  701.             /* open the mail file */
  702.             if (nntptrace >= 3)
  703.                 tprintf("Writing article to '%s'\n", buf);
  704.             if((fp = fopen(buf,APPEND_TEXT)) != NULLFILE) {
  705.                 fputs(froml,fp);
  706.                 rewind(tmpf);
  707.                 while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
  708.                     /* for UNIX mail compatiblity */
  709.                     if(strncmp(buf,"From ",5) == 0)
  710.                         putc('>',fp);
  711.                     fputs(buf,fp);
  712.                 }
  713.                 putc('\n',fp);
  714.                 fclose(fp);
  715.             }
  716.             rmlock(tempdir, prefix);
  717.             if (*cp == '\n') 
  718.                 break;
  719.             else
  720.                 sprintf(buf,"%s/",News_spool ? News_spool : Mailspool);
  721.             continue;
  722.         }
  723.         buf[strlen(buf)+1] = '\0';
  724.         buf[strlen(buf)] = strchr(validchars, tolower(*cp)) ? *cp : '_';
  725.     }
  726.     fclose(tmpf);
  727.     strcpy(buf,msgid);        /* Get a copy we can munge */
  728.     rip(buf);            /* remove trailing new-line */
  729.     rip(newgl);            /* ditto */
  730. #ifdef    notdef
  731.     tprintf("New news arrived: %s, article %s%c\n",newgl,buf,Smtpquiet?' ':'\007');
  732. #else
  733.     tprintf("New news arrived: %s, article %s\n",newgl,buf);
  734. #endif
  735.     return 0;
  736. }
  737.