home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / NNTPSERV.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  105KB  |  3,882 lines

  1. /*
  2.  *
  3.  * NNTP Server/Client - See RFC977
  4.  * Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
  5.  * Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
  6.  * Permission granted for non-commercial copying and use, provided
  7.  * this notice is retained.
  8.  *
  9.  * DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
  10.  * ported to NOS by PE1NMB - 920120
  11.  *
  12.  * DB3FL: ihave, read & lzw ported to NOS by YC1DAV 920804
  13.  *
  14.  * Mods by PA0GRI
  15.  *
  16.  * OH2BNS 9311xx: Fixed LIST, STAT, HEAD and BODY. Implemented POST.
  17.  *                Added 'nntp create'. Small fixes here and there...
  18.  *
  19.  * OH2BNS 9401xx: Rewrote STAT, HEAD, BODY, ARTICLE. Implemented
  20.  *                XHDR, XOVER, 'nntp access'. Rewrote garbled().
  21.  */
  22. #include <time.h>
  23. #include <stdarg.h>
  24. #include <ctype.h>
  25. #include <setjmp.h>
  26. #ifdef MSDOS
  27. #include <dos.h>
  28. #include <dir.h>
  29. #endif
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #ifdef LINUX
  33. #include <fcntl.h>
  34. #endif
  35. #ifdef MSDOS
  36. #include <io.h>
  37. #endif
  38. #include "global.h"
  39. #ifdef NNTPS
  40. #include "domain.h"
  41. #include "mbuf.h"
  42. #include "cmdparse.h"
  43. #include "socket.h"
  44. #include "iface.h"
  45. #include "proc.h"
  46. #include "smtp.h"
  47. #include "commands.h"
  48. #include "dirutil.h"
  49. #include "ftp.h"
  50. #include "netuser.h"
  51. #include "nntp.h"
  52. #include "session.h"
  53. #include "files.h"
  54. #include "smtp.h"
  55. #include "bm.h"
  56. #ifdef LESS_WHINING
  57. #include "pc.h"
  58. #include "nr4.h"
  59. #include "netrom.h"
  60. #include "udp.h"
  61. #include "tcp.h"
  62. #include "ip.h"
  63. #include "usock.h"
  64. #endif
  65. #ifdef LZW
  66. #include "lzw.h"
  67. #endif
  68.   
  69. FILE *open_file __ARGS((char *name,char *mode,int s,int t));
  70. FILE *temp_file __ARGS((int s,int t));          /* NMB */
  71.   
  72. static int near make_dir __ARGS((char *path,int s));
  73. static int check_file __ARGS((char *path));
  74. static int make_path __ARGS((char *group));
  75. static int check_blank __ARGS((char *bp));
  76. static int dup_f __ARGS((FILE *in,FILE *out,struct nntpsv *mp));
  77. static int update_list __ARGS((struct nntpsv *a));
  78. static int get_path2 __ARGS((struct article *art));
  79. static int dofwd __ARGS((struct nntpsv *mp,FILE *f,FILE *history));
  80. static int getreply __ARGS((struct nntpsv *cb));
  81. static int newnews __ARGS((char *string,struct nntpsv *mp,FILE *f));
  82. static int recv_file __ARGS((FILE *fp,int s));
  83. static int check_article __ARGS((char *id));
  84. static int xfer_article2 __ARGS((FILE *f,struct nntpsv *mp));
  85. static int retr_by_mid __ARGS((char *mid,struct nntpsv *mp));
  86. static int retr_by_num __ARGS((char *buf,struct nntpsv *mp));
  87. static int doarticlecmd __ARGS((char *buf,struct nntpsv *mp));
  88. static int doheadcmd __ARGS((char *buf,struct nntpsv *mp));
  89. static int dobodycmd __ARGS((char *buf,struct nntpsv *mp));
  90. static int dostatcmd __ARGS((char *buf,struct nntpsv *mp));
  91. static int doxhdrcmd __ARGS((char *buf,struct nntpsv *mp));
  92. static int doxovercmd __ARGS((char *buf,struct nntpsv *mp));
  93. static int restreql __ARGS((register char *w,register char *s));
  94. static int check_one __ARGS((register char *str));
  95. static int32 make_nntime __ARGS((struct date *d,struct time *t,char *str));
  96. static int ngmatcha __ARGS((int (*func)(char *,char *),int dflt,struct g_list *ngspec,struct g_list *matchlist));
  97. static int get_path __ARGS((char *group,struct nntpsv *mp));
  98. static int get_pointer __ARGS((char *group,struct nntpsv *mp));
  99. static FILE *open_message __ARGS((struct nntpsv *mp,FILE *f));
  100. static int get_id __ARGS((char *bp,struct nntpsv *mp));
  101. static int garbled __ARGS((FILE *inf,FILE *outf));
  102. static int donewnews __ARGS((char *string,struct nntpsv *mp));
  103. static int dogroup __ARGS((struct nntpsv *mp,char *buf));
  104. static int check_grp __ARGS((struct nntpsv *mp));
  105. static int get_next __ARGS((struct nntpsv *mp));
  106. static int get_last __ARGS((struct nntpsv *mp));
  107. void poll __ARGS((void *p));
  108. static int get_article2 __ARGS((struct nntpsv *mp,char *id));
  109. static int post_article __ARGS((struct nntpsv *mp));
  110. static int donnprofile __ARGS((int argc,char *argv[],void *p));
  111. static int chk_access __ARGS((int s));
  112. static int donnfirstpoll __ARGS((int argc,char *argv[],void *p));
  113. static void make_time_string(char *string,time_t *timep);
  114.   
  115. /***************************************************************************/
  116.   
  117. #undef CONTROL                  /* reverse NNTP function (not implemented yet) */
  118. #define LINE    80
  119. #ifdef LZW
  120. int LzwActive = 1;
  121. #endif
  122.   
  123. static int16 Nntpquiet = 0;
  124. static int16 NnIhave = 0;
  125. int Nntpaccess = 0;
  126. static int Nntpfirstpoll = 5;
  127. int Filecheck = 0;              /* flag if file system has been checked */
  128. long GMT_offset;                /* our offset from GMT, in seconds.  Positive if W Longitude. */
  129.   
  130. struct post *Post = NULLPOST;
  131. struct Servers *Nntpserver = NULLSERVER;
  132.   
  133. static char *Host       = NULLCHAR;
  134. static char NEol[]      = ".\n";
  135. static char replyto[]   = "Reply-To: ";
  136. /* RFC1036 required headers */
  137. static char frm[]       = "From: ";
  138. static char dte[]       = "Date: ";
  139. static char ngrps[]     = "Newsgroups: ";
  140. static char subj[]      = "Subject: ";
  141. static char msgid[]     = "Message-ID: ";
  142. static char pth[]       = "Path: ";
  143.   
  144. /*############################ NNTP COMMANDS #################################*/
  145.   
  146. /* Command table */
  147. static char *commands[] = {
  148.     "article",
  149. #define ARTICLE_CMD     0
  150.     "body",
  151. #define BODY_CMD        1
  152.     "debug",
  153. #define DEBUG_CMD       2
  154.     "group",
  155. #define GROUP_CMD       3
  156.     "head",
  157. #define HEAD_CMD        4
  158.     "help",
  159. #define HELP_CMD        5
  160.     "ihave",
  161. #define IHAVE_CMD       6
  162.     "last",
  163. #define LAST_CMD        7
  164.     "list",
  165. #define LIST_CMD        8
  166.     "newnews",
  167. #define NEWNEWS_CMD     9
  168.     "next",
  169. #define NEXT_CMD        10
  170.     "post",
  171. #define POST_CMD        11
  172.     "quit",
  173. #define QUIT_CMD        12
  174.     "slave",
  175. #define SLAVE_CMD       13
  176.     "stat",
  177. #define STAT_CMD        14
  178.     "xhdr",
  179. #define XHDR_CMD        15
  180.     "xinfo",
  181. #define XINFO_CMD       16
  182.     "xlzw",
  183. #define XLZW_CMD        17
  184.     "xover",
  185. #define XOVER_CMD       18
  186.     "newgroups",
  187. #define NEWGROUPS_CMD   19
  188.     NULLCHAR
  189. };
  190.   
  191. static char artmsg[]    = " Article retrieved - ";
  192. /*static char info[]      = "100 %s Info:\n";*/
  193. static char xinfo[]     = "100 No info available\n";
  194. static char debug[]     = "100 Debug %s\n";
  195. static char nnversion[] = "20%s %s NNTP version %s ready at %s %s\n";
  196. static char slave[]     = "202 Slave %s\n";
  197. static char closing[]   = "205 Closing\n";
  198. static char listarticle[]= "211 %u %u %u%s\n";
  199. static char listgroups[]= "215 List of newsgroups follows\n";
  200. static char newgroups[]    = "231 List of new newsgroups follows\n";
  201. static char retrieve[]  = "220 %u%s%shead and body follow\n";
  202. static char head[]      = "221 %u%s%sHead\n";
  203. static char xheader1[]  = "221 %s fields follow\n";
  204. static char xheader2[]  = "221 %u %s header of article %s\n";
  205. static char body[]      = "222 %u%s%sBody\n";
  206. static char statistics[]= "223 %u%s%sStatistics\n";
  207. static char sepcmd[]    = "223 %u %s%srequest text separately\n";
  208. static char xover[]     = "224 data follows\n";
  209. static char newnews_t[] = "230 New news by message id follows\n";
  210. static char transok[]   = "235 Thanks\n";
  211. static char postok[]    = "240 Article posted ok\n";
  212. static char sendart[]   = "335 Send article, end with .\n";
  213. static char sendpost[]  = "340 Send article to be posted, end with .\n";
  214. static char nogroup[]   = "411 No such newsgroup\n";
  215. static char noselect[]  = "412 No newsgroup selected\n";
  216. static char nonext[]    = "421 No next article\n";
  217. static char noprev[]    = "422 No previous article\n";
  218. static char noart[]     = "430 No such article\n";
  219. static char notwanted[] = "435 Article not wanted - do not send it\n";
  220. static char transnotok[]= "437 Article rejected - header garbled - do not try again\n";
  221. static char notallowed[]= "440 Posting not allowed\n";
  222. static char postfailed[]= "441 Posting failed";
  223. static char notrecognd[]= "500 Command not recognized\n";
  224. static char badsyntax[] = "501 Syntax error\n";
  225. static char noaccess[]  = "502 I'm not allowed to talk to you\n";
  226. static char error[]     = "503 Command not performed\n";
  227. /*static char nospace[]   = "503 Not enough disk space left\n"; */
  228. static char lowmem[]    = "503 System overloaded\n";
  229. static char fatal[]     = "503 Fatal error FILE %s\n";
  230. static char quitcmd[]   = "QUIT\n";
  231.   
  232. static void near
  233. rip2(register char *s)
  234. {
  235.     register char *cp;
  236.   
  237.     if((cp = strpbrk(s,"\r\n")) != NULLCHAR)
  238.         *cp = '\0';
  239. }
  240.   
  241. /* main directory-creating routine
  242.  * handles special chars in pathname - especially for MSDOS
  243.  * returncode: -1 error; 0 success
  244.  */
  245. static int near
  246. make_dir(path,s)
  247. char *path;
  248. int s;
  249. {
  250. #ifdef MSDOS
  251.     register char *cp;
  252. #endif
  253.   
  254.     if(path == NULLCHAR)
  255.         return -1;
  256.   
  257. #ifdef MSDOS
  258.     while((cp = strchr(path,'\\')) != NULLCHAR)
  259.         *cp = '/';
  260. #endif
  261.   
  262.     if (access(path,0)) {
  263. #ifdef UNIX
  264.         if (mkdir(path,0755)) {              /* 0755 is drwxr-xr-x */
  265. #else
  266.             if (mkdir(path)) {
  267. #endif
  268.                 tprintf("Can't create %s: %s\n",path,sys_errlist[errno]);
  269.                 if(s)
  270.                     usprintf(s,fatal,path);
  271.                 return -1;
  272.             }
  273.         }
  274.         return 0;
  275.     }
  276.   
  277.   
  278.   
  279. /* main message-opening routine
  280.  * returncode: NULLFILE if error; filepointer success */
  281.   
  282.     static FILE *
  283.     open_message(mp,f)
  284.     struct nntpsv *mp;
  285.     FILE *f;
  286.     {
  287.         char line[LineLen];
  288.   
  289.     /* mp already checked */
  290.   
  291.         if(f != NULLFILE)
  292.             fclose(f);
  293.   
  294.         sprintf(line,"%s/%u",mp->path,mp->pointer);
  295.   
  296.         if ((f = open_file(line,READ_TEXT,0,0)) == NULLFILE)
  297.             usputs(mp->s,"430 Error opening message - no such article.\n");
  298.   
  299.         return f;
  300.     }
  301.   
  302.   
  303.   
  304. /* file-receiving routine
  305.  * returncode: -1 if error or 'recvline' faults; 0 success; 1 if blank line */
  306.   
  307.     static int
  308.     recv_file(fp,s)
  309.     FILE *fp;
  310.     int s;
  311.     {
  312.         char line[LineLen];
  313.         int ret,check = 0;
  314.   
  315.         for (;;) {
  316.             if (recvline(s,line,LineLen) == -1)
  317.                 return -1;
  318.   
  319.   
  320.             rip2(line);
  321.   
  322.             if (strcmp(line,".") == 0)
  323.                 return 0;
  324.   
  325.             if(!check) {                    /* only enabled on first line! */
  326.                 check = 1;
  327.                 if (*line == '\0')          /* check for blank line */
  328.                     return 1;
  329.             }
  330.             fprintf(fp,"%s\n",line);
  331.         }
  332.     }
  333.   
  334.   
  335.   
  336. /* checks incoming article-id against existing articles
  337.  * returncode: -1 if error; 1 if article exists; 0 no article found */
  338.   
  339. /* Now also makes a crude format check - OH2BNS */
  340.   
  341.     static int
  342.     check_article(id)
  343.     char *id;
  344.     {
  345.         char *p, *p1, line[LineLen];
  346.         FILE *f;
  347.   
  348.         if(id == NULLCHAR || (p = strchr(id,'<')) == NULLCHAR
  349.             || (f = open_file(History,READ_TEXT,0,1)) == NULLFILE)
  350.             return -1;
  351.   
  352.         p1 = p;
  353.         while (*p1 != '\0' && *p1 != '>' && !isspace(*p1))
  354.             p1++;
  355.         if (*p1 != '>' || *++p1 != '\0')
  356.             return -1;
  357.   
  358.         for(;;) {
  359.             if (fgets(line,LineLen,f) == NULL) {
  360.                 fclose(f);
  361.                 return 0;
  362.             }
  363.   
  364.             if (!strncmp(line,p,strlen(p))) {
  365.                 fclose(f);
  366.                 return 1;
  367.             }
  368.         }
  369.         pwait(NULL);     /* let other processes run */
  370.     }
  371.   
  372.   
  373.   
  374. /* checks for not valid chars in a line
  375.  * returncode: 0 if valid; 1 if invalid */
  376.     static int
  377.     check_blank(bp)
  378.     char *bp;
  379.     {
  380.         if (strpbrk(bp,"!@#$%^&*()_+=<>,./?~`[]{}\\|0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == NULL)
  381.             return 1;
  382.         return 0;
  383.     }
  384.   
  385.   
  386.   
  387. /* main file-checking routine
  388.  * returncode: -1 if error; 0 success */
  389.     static int
  390.     check_file(path)
  391.     char *path;
  392.     {
  393.         if(path == NULLCHAR)
  394.             return -1;
  395.         if(access(path,0))
  396. #ifdef UNIX
  397.             return close(creat(path,0644));             /* 0644 is -rw-r--r-- */
  398. #else
  399.         return close(creat(path,S_IWRITE));
  400. #endif
  401.         return 0;
  402.     }
  403.   
  404. /* checks if two spaces exists in given string
  405.  * returncode: -1 if error; 1 success */
  406.     static int
  407.     check_one(str)
  408.     register char *str;
  409.     {
  410.         register char *cp;
  411.   
  412.         if(str == NULLCHAR || (cp = strchr(str,' ')) == NULLCHAR)
  413.             return -1;
  414.         cp++;
  415.   
  416.         if (strchr(cp,' ') == NULLCHAR)
  417.             return -1;
  418.   
  419.         return 1;
  420.     }
  421.   
  422. /* obtain offset from GMT, in seconds.  Positive if W Longitude. -- N5KNX */
  423. static long
  424. get_GMT_offset(void)
  425. {
  426.     struct tm *ltm;
  427.     time_t t;
  428.     int i;
  429.  
  430.     time(&t);
  431.     ltm = gmtime(&t);
  432.     i = ltm->tm_hour*60 + ltm->tm_min;
  433.     ltm = localtime(&t);
  434.     i -= (ltm->tm_hour*60 + ltm->tm_min);
  435.     return (long)i*60L;  /* in seconds */
  436. }
  437.  
  438. /* checks the file-system used for NNTP
  439.  * returncode: -1 if error; 0 success - and "Filecheck" is set to 1 */
  440.     static int
  441.     check_system(void)
  442.     {
  443.         FILE *f;
  444.         char line[LineLen];
  445.         int error = 0;
  446.   
  447.         if (Post == NULLPOST)
  448.             donnprofile(10,NULL,NULL);
  449.   
  450.         if(Filecheck)
  451.             return 0;
  452.   
  453.         error  = make_dir(Forward,0);
  454.         error |= check_file(Pointer);
  455.         error |= check_file(History);
  456.         error |= check_file(Active);
  457.         error |= check_file(Poll);
  458.         error |= check_file(Naccess);
  459.   
  460.         if(error)
  461.             goto quit;
  462.   
  463.         sprintf(line,"%s/fwd.seq",Newsdir);
  464.         if (access(line,0)) {
  465.             if((f = open_file(line,"w+",0,1)) == NULLFILE) {
  466.                 goto quit;
  467.             }
  468.             fputs("1\n",f);
  469.             fclose(f);
  470.         }
  471.   
  472.         sprintf(line,"%s/sequence.seq",Mailqdir);
  473.         if (access(line,0)) {
  474.             if((f = open_file(line,"w+",0,1)) == NULLFILE) {
  475.                 goto quit;
  476.             }
  477.             fputs("1\n",f);
  478.             fclose(f);
  479.         }
  480.   
  481.         GMT_offset = get_GMT_offset();
  482.  
  483.         Filecheck = 1;
  484.         return 0;
  485.   
  486.         quit:
  487.         Filecheck = 0;
  488.         tputs("Error in NNTP file system\n");
  489.         return -1;
  490.     }
  491.   
  492.   
  493.   
  494. /* handles the response code of an incoming msg
  495.  * returncode: -1 error; 0 no code; value of response code on success */
  496.   
  497.     static int
  498.     getreply(cb)
  499.     struct nntpsv *cb;
  500.     {
  501.         int response;
  502.   
  503.         while(recvline(cb->s,cb->buf,LineLen) != -1) {
  504.         /* skip informative messages and blank lines */
  505.             if(cb->buf[0] == '\0' || cb->buf[0] == '1')
  506.                 continue;
  507.   
  508.             sscanf(cb->buf,"%d",&response);
  509.             return (response < 500) ? response : -1;
  510.         }
  511.         return -1;
  512.     }
  513.   
  514.   
  515.   
  516. /* returncode: -1 error; 1 success; 0 no entry */
  517.   
  518.     static int
  519.     get_path(group,mp)
  520.     char *group;
  521.     struct nntpsv *mp;
  522.     {
  523.         FILE *f;
  524.         char line[LineLen], *cp;
  525.   
  526.         if(group == NULLCHAR || mp == NULLNNTPSV
  527.             || (f = open_file(Pointer,READ_TEXT,mp->s,0)) == NULLFILE)
  528.             return -1;
  529.   
  530.         group++;
  531.         for (;;) {
  532.             if (fgets(line,LineLen,f) == NULL)
  533.                 break;
  534.   
  535.             if (strcspn(line," ") != strlen(group))
  536.                 continue;
  537.   
  538.             if (strnicmp(group,line,strlen(group)) == 0) {
  539.                 cp = (strchr(line,' ')) + 1;
  540.   
  541.                 if (mp->path != NULLCHAR)
  542.                     free(mp->path);
  543.   
  544.                 mp->path = strdup(cp);
  545.                 rip2(mp->path);
  546.                 fclose(f);
  547.                 return 1;
  548.             }
  549.         }
  550.         fclose(f);
  551.         return 0;
  552.     }
  553.   
  554.   
  555.   
  556. /* checkes if path to given article exists
  557.  * returncode: -1 error; 1 success; 0 no path */
  558.   
  559.     static int
  560.     get_path2(art)
  561.     struct article *art;
  562.     {
  563.         FILE *f;
  564.         char line[LineLen], *p;
  565.   
  566.         if(art->group == NULLCHAR
  567.             || (f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
  568.             return -1;
  569.   
  570.         p = art->group;
  571.         art->path = NULLCHAR;
  572.   
  573.         for (;;) {
  574.             if (fgets(line,LineLen,f) == NULL)
  575.                 break;
  576.   
  577.             if (strcspn(line," ") != strlen(p))
  578.                 continue;
  579.   
  580.             if (strnicmp(p,line,strlen(p)) == 0) {
  581.                 p = (strchr(line,' ')) + 1;
  582.   
  583.                 if(art->path != NULLCHAR)
  584.                     free(art->path);
  585.   
  586.                 art->path = strdup(p);
  587.                 rip2(art->path);
  588.                 fclose(f);
  589.                 return 1;
  590.             }
  591.         }
  592.         fclose(f);
  593.         return 0;
  594.     }
  595.   
  596.   
  597.   
  598. /* returncode: -1 if error; 1 success; 0 no pointer */
  599.   
  600.     static int
  601.     get_pointer(group,mp)
  602.     char *group;
  603.     struct nntpsv *mp;
  604.     {
  605.         FILE *f;
  606.         char line[LineLen], *p;
  607.   
  608.         if(group == NULLCHAR || mp == NULLNNTPSV
  609.             || (f = open_file(Active,READ_TEXT,mp->s,0)) == NULLFILE)
  610.             return -1;
  611.   
  612.         group++;
  613.   
  614.         for (;;) {
  615.             if (fgets(line,LineLen,f) == NULL)
  616.                 break;
  617.   
  618.             if (strcspn(line," ") != strlen(group))
  619.                 continue;
  620.   
  621.             if (strnicmp(group,line,strlen(group))==0) {
  622.                 p = strchr(line,' ');
  623.                 mp->last = (unsigned)atoi(p);
  624.                 p++;
  625.                 mp->first = (unsigned)atoi(strchr(p,' '));
  626.                 mp->pointer = (mp->first > mp->last ) ? 0 : mp->first;
  627.                 fclose(f);
  628.                 return 1;
  629.             }
  630.         }
  631.         fclose(f);
  632.         return 0;
  633.     }
  634.   
  635.   
  636.   
  637. /* creating path to a new newsgroup
  638.  * handling of "." and "\" in pathnames especially MSDOS */
  639. /* returncode: -1 error; 0 success */
  640.   
  641.     static int
  642.     make_path(group)
  643.     char *group;
  644.     {
  645.         FILE *f;
  646.         char cp[LineLen], cp1[LineLen], *cp2;
  647.         int got_it;
  648.   
  649.         if (group == NULLCHAR
  650.             || (f = open_file(Pointer,APPEND_TEXT,0,1)) == NULLFILE)
  651.             return -1;
  652.   
  653.         got_it = 0;
  654.         strcpy(cp1,group);
  655.   
  656.         for(;;) {
  657.             if((cp2 = strchr(cp1,'.')) != NULLCHAR)
  658.                 *cp2 = '\0';
  659.             else
  660.                 got_it = 1;
  661.   
  662.             sprintf(cp,"%s/%s",Newsdir,cp1);
  663.   
  664.             if(make_dir(cp,0)) {
  665.                 fclose(f);
  666.                 return -1;
  667.             }
  668.   
  669.             if(got_it) {
  670.                 fprintf(f,"%s %s\n",group,cp);
  671.                 fclose(f);
  672.                 return 0;
  673.             }
  674.             *cp2 = '/';
  675.         }
  676.     }
  677.   
  678.   
  679.   
  680.     static int
  681.     update_list(a)
  682.     struct nntpsv *a;
  683.     {
  684.         FILE *f, *t;
  685.         char *p, *p1, l2[LineLen];
  686.   
  687.         if((f = open_file(Active,READ_TEXT,a->s,0)) == NULLFILE)
  688.             return -1;
  689.   
  690.         if ((t = temp_file(0,1)) == NULLFILE) {
  691.             fclose(f);
  692.             return -1;
  693.         }
  694.   
  695.         p1 = a->ap->group;
  696.         a->ap->number = 0;
  697.   
  698.         for (;;) {
  699.             if (fgets(a->buf,LineLen,f) == NULL)
  700.                 break;
  701.   
  702.             a->ap->tmpu = strcspn(a->buf," ");
  703.             strncpy(l2,a->buf,a->ap->tmpu);
  704.             l2[a->ap->tmpu] = '\0';
  705.   
  706.             p = strrchr(a->buf,' ') + 1;    /* the char after the last space */
  707.             if (*p == 'n') {            /* posting to this group not allowed */
  708.                 fputs(a->buf,t);
  709.                 continue;
  710.             }
  711.   
  712.             if (strcmp(p1,l2) == 0) {
  713.                 p = strchr(a->buf,' ') + 1;
  714.                 a->ap->number = (unsigned)atoi(p);
  715.                 (a->ap->number)++;
  716.                 p = strchr(p,' ');
  717.                 fprintf(t,"%s %5.5u%s",p1,a->ap->number,p);
  718.             } else
  719.                 fputs(a->buf,t);
  720.   
  721.         }
  722.   
  723.         fclose(f);
  724.         rewind(t);
  725.   
  726.         if ((f = open_file(Active,WRITE_TEXT,a->s,0)) == NULLFILE) {
  727.             fclose(t);
  728.             return -1;
  729.         }
  730.   
  731.         for(;;) {
  732.             pwait(NULL);
  733.             if (fgets(a->buf,LineLen,t) == NULL)
  734.                 break;
  735.   
  736.             fputs(a->buf,f);
  737.         }
  738.   
  739.         fclose(t);
  740.   
  741. /* Creating newsgroups by posting is now denied - OH2BNS
  742.  *
  743.  *   if (a->ap->number == 0) {
  744.  *       make_path(a->ap->group);
  745.  *       a->ap->number = 1;
  746.  *       fprintf(f,"%s 00001 00001 y\n",a->ap->group);
  747.  *   }
  748.  */
  749.   
  750.         fclose(f);
  751.         return (a->ap->number);
  752.     }
  753.   
  754.   
  755.   
  756. /* returncode: -1 error; 0 success */
  757.   
  758.     static int
  759.     dup_f(in,out,mp)
  760.     FILE *in;
  761.     FILE *out;
  762.     struct nntpsv *mp;
  763.   
  764. /* Path: bug in col 1 of article body bug fixed by G4JEC 901019....*/
  765.   
  766.     {
  767.         char *p;
  768.         int blank_line_flag = 1;
  769.   
  770.         for(;;) {
  771.             pwait(NULL);
  772.             if (fgets(mp->buf,LineLen,in) == NULL)
  773.                 return 0;
  774.   
  775.             if (blank_line_flag)
  776.                 if (strnicmp(mp->buf,pth,5) == 0) {
  777.                     p = strchr(mp->buf,' ') + 1;
  778.                     fprintf(out,"%s%s!%s",pth,Host,p);
  779.                     continue;
  780.                 }
  781.   
  782.         /* oh oh - nntpserv is modifying articles....*/
  783.   
  784.             if (strlen(mp->buf) == 1 && mp->buf[0] == '.')
  785.                 continue;
  786.   
  787.             fputs(mp->buf,out);
  788.   
  789.         /* ! removed. Now dup_f searches the whole header for "Path: ",
  790.          * not only the first line - OH2BNS */
  791.   
  792.             if(check_blank(mp->buf))
  793.                 blank_line_flag = 0;
  794.         }
  795.     }
  796.   
  797.   
  798.   
  799. /* returncode: < 1 if error; 1 success */
  800.   
  801.     static int
  802.     dofwd(mp,f,history)
  803.     struct nntpsv *mp;
  804.     FILE *f;
  805.     FILE *history;
  806.     {
  807.         FILE *fwd;
  808.   
  809.         if(mp == NULLNNTPSV)
  810.             return -1;
  811.   
  812.         sprintf(mp->buf,"%s/fwd.seq",Newsdir);
  813.   
  814.         if ((fwd = open_file(mp->buf,"r+",mp->s,0)) == NULLFILE)
  815.             return -1;
  816.   
  817.         fgets(mp->buf,LineLen,fwd);
  818.         mp->hold_i = atoi(mp->buf) + 1;
  819.         fprintf(history," JUNK/%u",mp->hold_i);
  820.         rewind(fwd);
  821.         fprintf(fwd,"%u",mp->hold_i);
  822.         fclose(fwd);
  823.   
  824.         sprintf(mp->buf,"%s/%u",Forward,mp->hold_i);
  825.   
  826.         if ((fwd = open_file(mp->buf,WRITE_TEXT,mp->s,0)) == NULLFILE)
  827.             return -2;
  828.   
  829.         rewind(f);
  830.         dup_f(f,fwd,mp);
  831.         fclose(fwd);
  832.         return 1;
  833.     }
  834.   
  835.   
  836.   
  837. #ifdef CONTROL
  838.   
  839.     static int
  840.     docontrol(f,mp)
  841.     FILE *f;
  842.     struct nntpsv *mp;
  843.     {
  844.         struct head *h;
  845.   
  846.         if(f == NULLFILE || mp == NULLNNTPSV
  847.             || (h = (struct head *)callocw(1,sizeof(struct head))) == NULLHEAD))
  848.             return -1;
  849.   
  850.         rewind(f);
  851.         h->subject = h->from = h->reply_to = h->id = NULLCHAR;
  852.   
  853.         for(;;) {
  854.             pwait(NULL);
  855.             if ((fgets(mp->buf,LineLen,f)) == NULL)
  856.                 break;
  857.   
  858.             if (check_blank(mp->buf))
  859.                 break;
  860.   
  861.             rip2(mp->buf);
  862.   
  863.             if (strncmp(mp->buf,subj,9) == 0)
  864.                 h->subject = strdup(mp->buf);
  865.   
  866.             if (strncmp(mp->buf,frm,6) == 0)
  867.                 h->from = strdup(mp->buf);
  868.   
  869.             if (strnicmp(mp->buf,replyto,10) == 0)
  870.                 h->reply_to = strdup(mp->buf);
  871.   
  872.             if (strnicmp(mp->buf,msgid,12) == 0)
  873.                 h->id = strdup(strchr(mp->buf,'<'));
  874.         }
  875.   
  876.         if (h->subject != NULLCHAR)
  877.             if (strncmp(h->subject,"Subject: sendme ",16) == 0)
  878.                 dosendme(h);
  879.   
  880.         if (h->subject != NULLCHAR)
  881.             free(h->subject);
  882.   
  883.         if (h->from != NULLCHAR)
  884.             free(h->from);
  885.   
  886.         if (h->reply_to != NULLCHAR)
  887.             free(h->reply_to);
  888.   
  889.         if (h->id != NULLCHAR)
  890.             free(h->id);
  891.   
  892.         free((char *)h);
  893.         return 0;
  894.     }
  895.   
  896. #endif
  897.   
  898.   
  899.   
  900.     static int
  901.     xfer_article2(f,mp)
  902.     FILE *f;
  903.     struct nntpsv *mp;
  904.     {
  905.         char line[LineLen], *p, *group = NULLCHAR, *p1, *from = NULLCHAR;
  906.         FILE *fptr, *history;
  907.         struct tm *stm;
  908.         int x=0;
  909.   
  910. #ifdef CONTROL
  911.         int control = 0;
  912. #endif
  913.   
  914.         long currtime;
  915.   
  916.         if(f == NULLFILE || mp == NULLNNTPSV)
  917.             return -1;
  918.   
  919.         while(mlock(History, NULLCHAR)) {
  920.             pause(1000L);
  921.             if (++x == 60) {
  922.                 log(-1, "NNTP: NEWS REJECTED due to history lock");
  923.                 return -1;   /* can't lock, so reject (what else? n5knx) */
  924.             }
  925.         }
  926.  
  927.     /* one last time check the message-id for duplicates */
  928.         if(check_article(mp->id) ||
  929.         (history = open_file(History,APPEND_TEXT,mp->s,0)) == NULLFILE) {
  930.             rmlock(History, NULLCHAR);
  931.             return -1;
  932.         }
  933.   
  934.         for (;;) {     /* obtain From: and Newsgroups: fields from article */
  935.             if (fgets(line,LineLen,f) == NULL)
  936.                 break;
  937.   
  938.             rip2(line);
  939.   
  940.             if (strnicmp(line,frm,6) == 0) {
  941.                 p = strchr(line,' ') + 1;
  942.                 from = strdup(p);
  943.                 if (group != NULLCHAR) break;
  944.                 continue;
  945.             }
  946.   
  947.             if (strnicmp(line,ngrps,12) == 0) {
  948.                 p = strchr(line,' ') + 1;
  949.                 group = strdup(p);
  950.                 if (from != NULLCHAR) break;
  951.                 continue;
  952.             }
  953.         }
  954.   
  955.         time(&currtime);
  956.         make_time_string(line,&currtime);
  957.         fprintf(history,"%s %s", mp->id, line);
  958.   
  959.         mp->hold_i = 0;
  960.         p = group;
  961.   
  962.         if((mp->ap = (struct article *)callocw(1,sizeof(struct article))) == NULLARTICLE)
  963.             goto quit;
  964.   
  965.         x = 1;
  966.   
  967.         while (x) {
  968.             if ((p1 = strchr(p,',')) != NULLCHAR) {
  969.                 p1 = line;
  970.   
  971.                 while (*p != ',')
  972.                     *(p1++)=*(p++);
  973.   
  974.                 *p1 = '\0';
  975.                 p++;
  976.                 mp->ap->group = strdup(line);
  977.             } else {
  978.                 mp->ap->group = strdup(p);
  979.                 x = 0;
  980.             }
  981.   
  982.             update_list(mp);
  983.   
  984.             if (mp->ap->number > 0) {
  985.                 get_path2(mp->ap);
  986.                 mp->hold_i = 1;
  987.                 sprintf(line,"%s/%u",mp->ap->path,mp->ap->number);
  988.                 rewind(f);
  989.   
  990.                 if ((fptr = open_file(line,WRITE_TEXT,mp->s,0)) == NULLFILE) {
  991.                     fclose(history);
  992.                     free(mp->ap->group);
  993.                     goto quit;
  994.                 }
  995.   
  996.                 dup_f(f,fptr,mp);
  997.                 fclose(fptr);
  998.                 fprintf(history," %s/%d",mp->ap->group,mp->ap->number);
  999.   
  1000. #ifdef CONTROL
  1001.                 if (strcmp(mp->ap->group,"control") == 0)
  1002.                     control = 1;
  1003. #endif
  1004.   
  1005.                 free(mp->ap->path);
  1006.             }
  1007.             free(mp->ap->group);
  1008.         }
  1009.   
  1010.         if (mp->hold_i == 0) {
  1011.             dofwd(mp,f,history);
  1012.             mp->hold_i = 0;
  1013.         }
  1014.   
  1015.         fputc('\n',history);
  1016.         fclose(history);
  1017.         time(&currtime);
  1018.   
  1019.         if(Nntpquiet < 2)
  1020.             tprintf("New mail in newsgroup %s\n  from <%s> at %s%s",
  1021.             (mp->hold_i) ? group : "JUNK",from,ctime(&currtime),
  1022.             (Nntpquiet < 1)  ? "\007" : "");
  1023.   
  1024. #ifdef CONTROL
  1025.         if (control == 1)
  1026.             docontrol(f,mp);
  1027. #endif
  1028.   
  1029.         quit:
  1030.   
  1031.         rmlock(History, NULLCHAR);
  1032.         free(from);
  1033.         free(group);
  1034.         free((char *)mp->ap);
  1035.         return (mp->hold_i);
  1036.     }
  1037.   
  1038.   
  1039.   
  1040.     static void
  1041.     nntppoll(unused,cb1,p)
  1042.     int unused;
  1043.     void *cb1;
  1044.     void *p;
  1045.     {
  1046.         char *cp, line[LineLen];
  1047.         struct sockaddr_in fsocket;
  1048.         struct nntpsv *cb;
  1049.         struct tm *stm, *ltm;
  1050.         FILE *f, *f1, *pf;
  1051.         long t;
  1052.         int r, now, ret;
  1053.         struct Servers *sp = (struct Servers *) cb1;
  1054.         long currtime;
  1055.         char open_time[15];
  1056.   
  1057.         if (!run_timer(&sp->nntpt))             /* if timer had stopped there is an
  1058.         return;                                          * active session */
  1059.   
  1060.             if (!Filecheck)
  1061.                 if(check_system())
  1062.                     return;
  1063.   
  1064.         if(availmem() < Memthresh) {
  1065.             start_timer(&sp->nntpt);
  1066.             return;
  1067.         }
  1068.   
  1069.     /* check connection window */
  1070.   
  1071.         time(&currtime);
  1072.         ltm = localtime(&currtime);
  1073.         now = ltm->tm_hour * 100 + ltm->tm_min;
  1074.   
  1075.         if (sp->lowtime < sp->hightime) {
  1076.         /* doesn't cross midnight */
  1077.             if (now < sp->lowtime || now >= sp->hightime) {
  1078.                 start_timer(&sp->nntpt);
  1079.                 return;
  1080.             }
  1081.         } else {
  1082.             if (now < sp->lowtime && now >= sp->hightime) {
  1083.                 start_timer(&sp->nntpt);
  1084.                 return;
  1085.             }
  1086.         }
  1087.   
  1088.         if((pf = open_file(Poll,"r+",0,1)) == NULLFILE ||
  1089.         (cb = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
  1090.             start_timer(&sp->nntpt);
  1091.             return;
  1092.         }
  1093.   
  1094.         stop_timer(&sp->nntpt);
  1095.   
  1096.         cb->fname   = NULLCHAR;
  1097.         cb->newnews = NULLCHAR;
  1098.         rewind(pf);
  1099.   
  1100.         for(t = 0L; fgets(line,LineLen,pf) != NULLCHAR; t = ftell(pf)) {
  1101.             if((cp = strchr(line,' ')) == NULLCHAR)
  1102.                 continue;           /* something wrong with this line, skip it */
  1103.   
  1104.             *cp = '\0';
  1105.   
  1106.             if(strnicmp(line,sp->name,strcspn(line," ")-1) == 0) {
  1107.                 rip2(cp+1);
  1108.                 cb->newnews = strdup(cp+1);
  1109.             /* Prepare to write back the current host and date */
  1110.                 fseek(pf,t,0);
  1111.                 break;
  1112.             }
  1113.         }
  1114.   
  1115.     if(cb->newnews == NULLCHAR) {
  1116.         if (Nntpfirstpoll < 0) {
  1117.             cb->newnews = strdup("900101 000000");
  1118.         } else {    /* from G8FSL */
  1119.             cb->newnews = mallocw(15);
  1120.             time(&currtime);
  1121.             currtime -= Nntpfirstpoll*86400L;
  1122.             make_time_string(cb->newnews,&currtime);
  1123.         }
  1124.     }
  1125.   
  1126.         fsocket.sin_family = AF_INET;
  1127.         fsocket.sin_addr.s_addr = cb->dest = sp->dest;
  1128.         fsocket.sin_port = IPPORT_NNTP;
  1129.   
  1130.         if((cb->s = socket(AF_INET,SOCK_STREAM,0)) == -1)
  1131.             goto quit;
  1132.   
  1133.         sockmode(cb->s,SOCK_ASCII);
  1134.   
  1135.         if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == -1)
  1136.             goto quit;
  1137.   
  1138.         log(cb->s,"Connect NNTP");
  1139.         time(&currtime);
  1140.         currtime -= 300L;    /* 5 mins rewind bodge against clock errs, G8FSL */
  1141.         make_time_string(open_time, &currtime);
  1142.   
  1143.         if(getreply(cb) == -1)          /* throw away any hello msg */
  1144.             goto quit;
  1145.   
  1146.     /* IHAVE preparation */
  1147.   
  1148.         if(NnIhave && (cb->ihave = tmpfile()) != NULLFILE) {
  1149.             sprintf(line,"%s %s",NnIhave == 2 ? "*" : sp->newsgroups,cb->newnews);
  1150.   
  1151.             if(newnews(line,cb,cb->ihave) < 1) {
  1152.                 fclose(cb->ihave);
  1153.                 cb->ihave = NULLFILE;
  1154.             }
  1155.         }
  1156.   
  1157. #ifdef LZW
  1158.         if (LzwActive)   {
  1159.             usprintf(cb->s,"XLZW %d %d\n",Lzwbits,Lzwmode);
  1160.             if((ret = getreply(cb)) == 235)   {       /* eat negative response */
  1161.                 lzwinit(cb->s,Lzwbits,Lzwmode);
  1162.             }
  1163.         }
  1164. #endif
  1165.   
  1166. #ifdef XXX
  1167.         usputs(cb->s,"SLAVE\n");
  1168.         if(getreply(cb) != 202)
  1169.             goto quit;
  1170. #endif
  1171.   
  1172.         cb->slave = 1;
  1173.   
  1174.         if ((f = temp_file(0,1)) == NULLFILE)
  1175.             goto quit;
  1176.   
  1177.         usprintf(cb->s,"NEWNEWS %s %s%s\n",
  1178.             (sp->newsgroups==NULLCHAR ? "*" : sp->newsgroups), cb->newnews,
  1179.             (GMT_offset ? "" : " GMT") );
  1180.   
  1181.         if(getreply(cb) != 230) {
  1182.             goto doihave;
  1183.         }
  1184.   
  1185.         if(recv_file(f,cb->s) == -1) {
  1186.             goto doihave;
  1187.         }
  1188.   
  1189.         if ((f1 = temp_file(cb->s,1)) == NULLFILE) {
  1190.             goto doihave;
  1191.         }
  1192.   
  1193.         rewind(f);
  1194.   
  1195.         for(;;) {
  1196.             if (fgets(cb->buf,LineLen,f) == NULL)
  1197.                 break;
  1198.   
  1199.             rip2(cb->buf);
  1200.   
  1201.             if (strcmp(cb->buf,".") == 0)
  1202.                 break;
  1203.   
  1204.             if (check_article(cb->buf) != 0)
  1205.                 continue;
  1206.   
  1207.             usprintf(cb->s,"ARTICLE %s\n",cb->buf);
  1208.   
  1209.             for (;;) {
  1210.                 if ((r = recvline(cb->s,cb->buf,LineLen)) == -1)
  1211.                     break;
  1212.   
  1213.                 rip2(cb->buf);
  1214.   
  1215.                 if(!isdigit(cb->buf[0])) {
  1216.                     r = -1;
  1217.                     continue;
  1218.                 } else {
  1219.                     r = atoi(cb->buf);
  1220.                     break;
  1221.                 }
  1222.             }
  1223.   
  1224.             if(r == -1)
  1225.                 break;
  1226.   
  1227.             if (r == 220) {
  1228.                 recv_file(f1,cb->s);
  1229.                 rewind(f1);
  1230.                 for ( ;; ) {
  1231.                     if (fgets(cb->buf,LineLen,f1) == NULL)
  1232.                         break;
  1233.   
  1234.                     rip2(cb->buf);
  1235.   
  1236.                     if (strnicmp(cb->buf,msgid,12) == 0) {
  1237.                         cb->id = strdup((strchr(cb->buf,' ')) + 1);
  1238.                         break;
  1239.                     }
  1240.                 }
  1241.   
  1242.                 rewind(f1);
  1243.                 xfer_article2(f1,cb);
  1244.                 free(cb->id);
  1245.             }
  1246.   
  1247.             fclose(f1);
  1248.   
  1249.             if ((f1 = temp_file(cb->s,1)) == NULLFILE)
  1250.                 goto doihave;
  1251.             pwait(NULL);
  1252.         }
  1253.   
  1254.         fclose(f1);
  1255.   
  1256.         doihave:    /* IHAVE offer */
  1257.   
  1258.         if(NnIhave && cb->ihave != NULLFILE) {
  1259.             rewind(cb->ihave);
  1260.   
  1261.             while(fgets(line,sizeof(line),cb->ihave),!feof(cb->ihave)) {
  1262.                 pwait(NULL);
  1263.                 usprintf(cb->s,"IHAVE %s",line);
  1264.   
  1265.                 if((ret = getreply(cb)) == -1)
  1266.                     break;
  1267.   
  1268.                 if(ret != 335)
  1269.                     continue;
  1270.   
  1271.                 rip2(line);
  1272.   
  1273.                 if(doarticlecmd(line,cb) == 0) {
  1274.                     usputs(cb->s,NEol);
  1275.   
  1276.                     if((ret = getreply(cb)) == -1)
  1277.                         break;
  1278.   
  1279.                     continue;
  1280.                 }
  1281.   
  1282.                 if((ret = getreply(cb)) != 235)
  1283.                     continue;
  1284.             }
  1285.   
  1286.             fclose(cb->ihave);
  1287.         }
  1288.   
  1289.         fclose(f);
  1290.   
  1291.         quit:
  1292.   
  1293.         usputs(cb->s,quitcmd);
  1294.         if (recvline(cb->s,cb->buf,LineLen) == -1);
  1295.   
  1296.     /*
  1297.      * update pollfile
  1298.      */
  1299.   
  1300.         if(errno == 0) {
  1301.         /* Now write back the opening date and time */
  1302.             fprintf(pf,"%s %s\n", sp->name, open_time);
  1303.         }
  1304.   
  1305.         fclose(pf);
  1306.         close_s(cb->s);
  1307.         free(cb->newnews);
  1308.         free((char *)cb);
  1309.         start_timer(&sp->nntpt);
  1310.     }
  1311.   
  1312.   
  1313.   
  1314.     static int
  1315.     ngmatcha(func,dflt,ngspec,matchlist)
  1316.     int     (*func)(char *,char *);
  1317.     int     dflt;
  1318.     struct g_list *ngspec;
  1319.     struct g_list *matchlist;
  1320.     {
  1321.         register int    match;
  1322.         char   *cp;
  1323.         struct g_list   *m,*n;
  1324.   
  1325.         match = dflt;
  1326.         m = matchlist;
  1327.         for(;;) {
  1328.             if ((cp = strchr(m->str,'/')) != NULLCHAR)
  1329.                 *cp = '\0';
  1330.             n = ngspec;
  1331.             for (;;) {
  1332.                 if (n->str[0] == '!') {      /* Handle negation */
  1333.                     if ((*func)(n->str+1, m->str)) {
  1334.                         match = 0;
  1335.                     }
  1336.                 } else {
  1337.                     if ((*func)(n->str, m->str)) {
  1338.                         match = 1;
  1339.                     }
  1340.                 }
  1341.                 if (n->next == NULLG)
  1342.                     break;
  1343.                 else
  1344.                     n=n->next;
  1345.             }
  1346.             if (m->next == NULLG)
  1347.                 break;
  1348.             else
  1349.                 m=m->next;
  1350.         }
  1351.         return (match);
  1352.     }
  1353.   
  1354.   
  1355.   
  1356.     static int
  1357.     restreql(w, s)
  1358.     register char *w;
  1359.     register char *s;
  1360.     {
  1361.         while (*s && *w) {
  1362.             switch (*w) {
  1363.                 case '*':
  1364.                     for (w++; *s; s++)
  1365.                         if (restreql(w, s))
  1366.                             return 1;
  1367.                     break;
  1368.                 default:
  1369.                     if (*w != *s)
  1370.                         return 0;
  1371.                     w++, s++;
  1372.                     break;
  1373.             }
  1374.         }
  1375.         if (*s)
  1376.             return 0;
  1377.   
  1378.         while (*w)
  1379.             if (*w++ != '*')
  1380.                 return 0;
  1381.   
  1382.         return 1;
  1383.     }
  1384.   
  1385.   
  1386.   
  1387. /* converts timestring to unix-compatible structure
  1388.  * str -> YYMMDD HHMMSS [GMT]
  1389.  * returncode: 0 (!!) if error; > 0 success */
  1390.   
  1391.     static int32
  1392.     make_nntime(d,t,str)
  1393.     struct date *d;
  1394.     struct time *t;
  1395.     char *str;
  1396.   
  1397.     {
  1398.   
  1399.         register char *cp;
  1400.         char tmp[3];
  1401.         int32 tim;
  1402.  
  1403.         if(str == NULLCHAR)
  1404.             return 0L;
  1405.         tmp[2] = '\0';
  1406.         cp = str;
  1407.         strncpy(tmp,cp,2);
  1408.         d->da_year = atoi(tmp)+1900;
  1409.         if (d->da_year < 1950)
  1410.             d->da_year += 100;  /* next century */
  1411.         if (d->da_year < 1980)
  1412.             d->da_year = 1980;
  1413.         cp+=2;
  1414.         strncpy(tmp,cp,2);
  1415.         d->da_mon = atoi(tmp);
  1416.         if (d->da_mon < 1 || d->da_mon > 12)
  1417.             return 0L;
  1418.         cp+=2;
  1419.         strncpy(tmp,cp,2);
  1420.         d->da_day = atoi(tmp);
  1421.         if (d->da_day < 1 || d->da_day > 32)
  1422.             return 0L;
  1423.         cp+=3;
  1424.         strncpy(tmp,cp,2);
  1425.         t->ti_hour = atoi(tmp);
  1426.         if (t->ti_hour >=1 && t->ti_hour <= 23 || t->ti_hour==0){
  1427.             cp+=2;
  1428.             strncpy(tmp,cp,2);
  1429.             t->ti_min = atoi(tmp);
  1430.         }else{
  1431.             return 0L;
  1432.         }
  1433.         if (t->ti_min >= 1 && t->ti_min <= 59 || t->ti_min==0){
  1434.             cp+=2;
  1435.             strncpy(tmp,cp,2);
  1436.             t->ti_sec = atoi(tmp);
  1437.         }else{
  1438.             return 0L;
  1439.         }
  1440.         if (t->ti_sec >= 1 && t->ti_sec <= 59 || t->ti_sec==0){
  1441.             t->ti_hund = 0;
  1442.             tim = dostounix(d,t);
  1443.             if (*(cp+3) == 'G') tim -= GMT_offset;   /* remove bias applied by dostounix */
  1444.             return tim;
  1445.         }else{
  1446.             return 0L;
  1447.         }
  1448.     }
  1449.   
  1450.   
  1451.   
  1452. /* returncode: -1 if error; 0 if no new news; 1 new news available */
  1453.   
  1454.     static int
  1455.     newnews(string,mp,f)
  1456.     char *string;
  1457.     struct nntpsv *mp;
  1458.     FILE *f;
  1459.   
  1460.     {
  1461.         register int i,j;
  1462.         char *cp, *cp1, line[LineLen], groups[LineLen];
  1463.         struct g_list *ng, *hist, *ngp, *histp, *ptr;
  1464.         FILE *f1;
  1465.         int all = 1;
  1466.   
  1467.         if (check_one(string) == -1)
  1468.             return -1;
  1469.   
  1470.         cp = string;
  1471.         i = 1;
  1472.   
  1473.         while (*(cp++) > 32)
  1474.             i++;
  1475.         if (strlen(cp) < 13)
  1476.             return -1;
  1477.   
  1478.         strncpy(groups,string,i-1);
  1479.         groups[i-1] = '\0';
  1480.         if(strcmp(groups,"*") != 0)
  1481.             all = 0;
  1482.   
  1483.         mp->datest = (struct date *)callocw(1,sizeof(struct date));
  1484.         mp->timest = (struct time *)callocw(1,sizeof(struct time));
  1485.         gettime(mp->timest);
  1486.         getdate(mp->datest);
  1487.   
  1488.         if ((mp->unixtime = make_nntime(mp->datest,mp->timest,cp)) == 0)
  1489.             goto quit;
  1490.         if (mp->unixtime == -1L)
  1491.             return 0;
  1492.   
  1493.         if (!all) {
  1494.             ng = ngp = (struct g_list *)callocw(1,(sizeof(struct g_list)));
  1495.             cp = groups;
  1496.   
  1497.             for (;;) {
  1498.                 if ((cp1 = strchr(cp,',')) == NULLCHAR ) {
  1499.                     ng->str = strdup(cp);
  1500.                     ng->next = NULLG;
  1501.                     break;
  1502.                 }
  1503.                 j = strcspn(cp,",");
  1504.                 ng->str = (char *)callocw(1,j+1);
  1505.                 strncpy(ng->str,cp,j);
  1506.                 ng->str[j] = '\0';
  1507.                 ng->next = (struct g_list *)callocw(1,sizeof(struct g_list));
  1508.                 ng = ng->next;
  1509.                 cp1 = strchr(cp,',');
  1510.                 if (cp1 != NULLCHAR)
  1511.                     cp = cp1 + 1;
  1512.                 else
  1513.                     break;
  1514.             }
  1515.         }
  1516.   
  1517.         if ((f1 = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
  1518.             goto quit;
  1519.   
  1520.         for (;;) {
  1521.             pwait(NULL);
  1522.             if (fgets(line,LineLen,f1) == NULL)
  1523.                 break;
  1524.             rip2(line);
  1525.   
  1526.             if (!all) {
  1527.                 for(i = 3, cp = line; i; --i)
  1528.                     cp = strchr(cp,' ') + 1;
  1529.                 histp = (struct g_list *)callocw(1,sizeof(struct g_list));
  1530.                 hist = histp;
  1531.   
  1532.                 for (;;) {
  1533.                     if ((cp1 = strchr(cp,' ')) == NULLCHAR) {
  1534.                         hist->str = strdup(cp);
  1535.                         hist->next = NULLG;
  1536.                         break;
  1537.                     }
  1538.   
  1539.                     j = strcspn(cp," ");
  1540.                     hist->str = (char *)callocw(1,j+1);
  1541.                     strncpy(hist->str,cp,j);
  1542.                     hist->str[j] = '\0';
  1543.                     hist->next = (struct g_list *)callocw(1,sizeof(struct g_list));
  1544.                     hist = hist->next;
  1545.                     cp1 = strchr(cp,' ');
  1546.                     if (cp1 != NULLCHAR)
  1547.                         cp = cp1 + 1;
  1548.                     else
  1549.                         break;
  1550.                 }
  1551.                 if (!ngmatcha(restreql,0,ngp,histp)) {
  1552.                     ptr = histp;
  1553.                     for (;;) {
  1554.                         ptr = histp->next;
  1555.                         free(histp->str);
  1556.                         free(histp);
  1557.                         histp = ptr;
  1558.                         if (histp == NULLG)
  1559.                             break;
  1560.                     }
  1561.                     continue;
  1562.                 }
  1563.             }
  1564.  
  1565.             cp = strchr(line,' ') + 1;
  1566.             if ((mp->ftime = make_nntime(mp->datest,mp->timest,cp)) == 0) {
  1567.                 fclose(f1);
  1568.                 goto quit;
  1569.             }
  1570.  
  1571.             if ((mp->ftime - mp->unixtime) > 0) {
  1572.                 cp = line;
  1573.                 while ( *cp > 32 )
  1574.                     fputc(*(cp++),f);
  1575.                 fputc('\n',f);
  1576.             }
  1577.  
  1578.             if (!all) {
  1579.                 ptr = histp;
  1580.                 for (;;) {
  1581.                     ptr = histp->next;
  1582.                     free(histp->str);
  1583.                     free(histp);
  1584.                     histp = ptr;
  1585.                     if (histp == NULLG)
  1586.                         break;
  1587.                 }
  1588.             }
  1589.         }
  1590.         fclose(f1);
  1591.         if (!all) {
  1592.             ptr = ngp;
  1593.             for (;;) {
  1594.                 ptr = ngp->next;
  1595.                 free(ngp->str);
  1596.                 free(ngp);
  1597.                 ngp = ptr;
  1598.                 if (ngp == NULLG)
  1599.                     break;
  1600.             }
  1601.         }
  1602.         free(mp->datest);
  1603.         free(mp->timest);
  1604.         return 1;
  1605.         quit:
  1606.         return 0;
  1607.     }
  1608.   
  1609. /* handles incoming newnews-cmd
  1610.  * returncode: -1 if error; 0 no groups or bad syntax; 1 success */
  1611.   
  1612.     static int
  1613.     donewnews(string,mp)
  1614.     char *string;
  1615.     struct nntpsv *mp;
  1616.   
  1617.     {
  1618.         FILE *f;
  1619.         int ret;
  1620.   
  1621.         if((f = temp_file(mp->s,1)) == NULLFILE)
  1622.             return -1;
  1623.   
  1624.         ret = newnews(string,mp,f);
  1625.   
  1626.         switch(ret) {
  1627.             case -1:                        /* error in "newnews" routine */
  1628.                 ret = 0;
  1629.                 usputs(mp->s,badsyntax);
  1630.                 break;
  1631.             case 0:                         /* no new news */
  1632.                 usputs(mp->s,newnews_t);
  1633.                 usputs(mp->s,NEol);
  1634.                 break;
  1635.             default:                        /* new news available, send news file */
  1636.                 rewind(f);
  1637.                 usputs(mp->s,newnews_t);
  1638.                 sendfile(f,mp->s,ASCII_TYPE,0,NULL);
  1639.                 usputs(mp->s,NEol);
  1640.                 ret = 1;
  1641.                 break;
  1642.         }
  1643.         fclose(f);
  1644.         return ret;
  1645.     }
  1646.   
  1647. /* change current newsgroup
  1648.  * returncode: -1 if error; 0 success; 1 no newsgroup */
  1649.   
  1650.     static int
  1651.     dogroup(mp,buf)
  1652.     struct nntpsv *mp;
  1653.     char *buf;
  1654.     {
  1655.         char *p;
  1656.         int er;
  1657.   
  1658.         if((p = strchr(buf,' ')) == NULLCHAR)
  1659.             return -1;
  1660.   
  1661.         er = get_path(p,mp);
  1662.   
  1663.         switch (er) {
  1664.   
  1665.             case 0:
  1666.                 usputs(mp->s,nogroup);
  1667.                 return 1;
  1668.   
  1669.             default:
  1670.                 p = strchr(buf,' ');
  1671.                 if (get_pointer(p,mp) == 1) {
  1672.                     usprintf(mp->s,listarticle,
  1673.                     mp->last - mp->first + 1,mp->first,mp->last,strchr(buf,' '));
  1674.                     return 0;
  1675.                 }
  1676.   
  1677.             case -1:
  1678.                 usputs(mp->s,error);
  1679.                 return -1;
  1680.         }
  1681.     }
  1682.   
  1683.   
  1684.   
  1685.   
  1686.   
  1687. /* checks if newsgroup is selected
  1688.  * returncode: -1 no group selected; 0 success */
  1689.   
  1690.     static int
  1691.     check_grp(mp)
  1692.     struct nntpsv *mp;
  1693.     {
  1694.         if(mp == NULLNNTPSV || mp->path == NULLCHAR) {
  1695.             usputs(mp->s,noselect);
  1696.             return -1;
  1697.         }
  1698.         return 0;
  1699.     }
  1700.   
  1701.   
  1702.   
  1703. /* get id-number of message
  1704.  * returncode: -1 if error; 0 if no message; 1 success */
  1705.   
  1706.     static int
  1707.     get_id(bp,mp)
  1708.     char *bp;
  1709.     struct nntpsv *mp;
  1710.     {
  1711.         FILE *f;
  1712.         char tmp[LineLen];
  1713.   
  1714.         if ((f = open_message(mp,NULLFILE)) == NULLFILE)
  1715.             return 0;
  1716.   
  1717.         for (;;) {
  1718.             if (fgets(tmp,LineLen,f) == NULL)
  1719.                 break;
  1720.   
  1721.             if (check_blank(tmp))
  1722.                 break;
  1723.   
  1724.             if (strnicmp(tmp,msgid,12)==0) {
  1725.                 fclose(f);
  1726.                 strcpy(bp,strchr(tmp,' '));
  1727.                 rip2(bp);
  1728.                 return 1;
  1729.             }
  1730.         }
  1731.         fclose(f);
  1732.         strcpy(bp,"\0");
  1733.         return 0;
  1734.     }
  1735.   
  1736.   
  1737.   
  1738. /* gets next news of newsgroup
  1739.   
  1740.  * returncode: -1 if error; 0 no news; 1 success */
  1741.   
  1742.     static int
  1743.     get_next(mp)
  1744.     struct nntpsv *mp;
  1745.   
  1746.     {
  1747.         FILE *f;
  1748.   
  1749.         for (;;) {
  1750.             if (mp->pointer == 0 ) {
  1751.                 usputs(mp->s,nonext);
  1752.                 return 0;
  1753.             }
  1754.  
  1755.             if (++(mp->pointer) > mp->last) {
  1756.                 mp->pointer--;
  1757.                 usputs(mp->s,nonext);
  1758.                 return 0;
  1759.             }
  1760.  
  1761.             sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
  1762.             if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
  1763.                 fclose(f);
  1764.                 return 1;
  1765.             }
  1766.         }
  1767.     }
  1768.   
  1769.   
  1770. /* gets last news of newsgroup
  1771.   
  1772.  * returncode: -1 if error; 0 no news; 1 success */
  1773.   
  1774.     static int
  1775.     get_last(mp)
  1776.     struct nntpsv *mp;
  1777.     {
  1778.         FILE *f;
  1779.   
  1780.         for (;;) {
  1781.             if (mp->pointer == 0) {
  1782.                 usputs(mp->s,noprev);
  1783.                 return 0;
  1784.             }
  1785.   
  1786.             if (--(mp->pointer) < mp->first) {
  1787.                 mp->pointer++;
  1788.                 usputs(mp->s,noprev);
  1789.                 return 0;
  1790.             }
  1791.   
  1792.             sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
  1793.             if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
  1794.                 fclose(f);
  1795.                 return 1;
  1796.             }
  1797.         }
  1798.     }
  1799.   
  1800.   
  1801. /*
  1802.  * Retrieves article by message-id. Sets mp->pointer and mp->path.
  1803.  * Return: success 0, no article 1, error -1.
  1804.  */
  1805.   
  1806.     static int
  1807.     retr_by_mid(mid,mp)
  1808.     char *mid;
  1809.     struct nntpsv *mp;
  1810.     {
  1811.         FILE *f;
  1812.         char *p,*p1,line[LineLen];
  1813.   
  1814.         if((f = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
  1815.             return -1;
  1816.   
  1817.         for(;;) {
  1818.             if(fgets(line,LineLen-1,f) == NULLCHAR) {
  1819.                 usputs(mp->s,noart);
  1820.                 fclose(f);
  1821.                 return 1;
  1822.             }
  1823.             if(strncmp(line,mid,strlen(mid)) == 0)
  1824.                 break;
  1825.         }
  1826.   
  1827.         p = strchr(line,' ') + 14;  /* point to the space before first newsgroup */
  1828.         p1 = strchr(p,'/');
  1829.         *p1 = '\0';
  1830.         p1++;
  1831.         mp->pointer = atoi(p1);                       /* get the article number */
  1832.   
  1833.         if(mp->path != NULLCHAR)
  1834.             free(mp->path);
  1835.   
  1836.         if(strcmp(p,"JUNK") == 0)
  1837.             mp->path = strdup(Forward);
  1838.         else
  1839.             get_path(p,mp);
  1840.   
  1841.         fclose(f);
  1842.         return 0;
  1843.     }
  1844.   
  1845.   
  1846. /*
  1847.  * Retrieves article by article number. Sets mp->pointer.
  1848.  * Return: success 0, no article 1, error -1.
  1849.  */
  1850.   
  1851.     static int
  1852.     retr_by_num(buf,mp)
  1853.     char *buf;
  1854.     struct nntpsv *mp;
  1855.     {
  1856.         int n;
  1857.         char *p;
  1858.   
  1859.         if(check_grp(mp))
  1860.             return 1;
  1861.   
  1862.         if((p = strchr(buf,' ')) == NULLCHAR || check_blank(p))
  1863.             return 0;
  1864.   
  1865.         p++;
  1866.         n = atoi(p);
  1867.         if(!n || n > mp->last || n < mp->first) {
  1868.             usputs(mp->s,noart);
  1869.             return 1;
  1870.         }
  1871.         mp->pointer = n;
  1872.         return 0;
  1873.     }
  1874.   
  1875.   
  1876. /*
  1877.  * Do ARTICLE command. Return: success 0, no article 1, error -1.
  1878.  */
  1879.   
  1880.     static int
  1881.     doarticlecmd(buf,mp)
  1882.     char *buf;
  1883.     struct nntpsv *mp;
  1884.     {
  1885.         FILE *f;
  1886.         char *p,*hold_s;
  1887.         int ret,hold_i,hold = 0;
  1888.   
  1889.         if((p = strchr(buf,'<')) != NULLCHAR) {
  1890.             hold = 1;
  1891.             hold_i = mp->pointer;
  1892.             hold_s = mp->path;
  1893.             mp->path = NULLCHAR;
  1894.             if((ret = retr_by_mid(p,mp)) != 0)
  1895.                 return ret;
  1896.         }
  1897.         else if((ret = retr_by_num(buf,mp)) != 0)
  1898.             return ret;
  1899.   
  1900.         if (get_id(mp->buf,mp) != 1)
  1901.             return -1;
  1902.   
  1903.         f = NULL;   /* WG7J */
  1904.         if ((f = open_message(mp,f)) == NULLFILE)
  1905.             return -1;
  1906.   
  1907.         usprintf(mp->s,retrieve,mp->pointer,mp->buf,artmsg);
  1908.         sendfile(f, mp->s, ASCII_TYPE,0,NULL);
  1909.         usputs(mp->s,NEol);
  1910.   
  1911.         if(hold) {
  1912.             mp->pointer = hold_i;
  1913.             free(mp->path);
  1914.             mp->path = hold_s;
  1915.         }
  1916.         fclose(f);
  1917.         return 0;
  1918.     }
  1919.   
  1920.   
  1921. /*
  1922.  * Do HEAD command. Return: success 0, no article 1, error -1.
  1923.  */
  1924.   
  1925.     static int
  1926.     doheadcmd(buf,mp)
  1927.     char *buf;
  1928.     struct nntpsv *mp;
  1929.     {
  1930.         FILE *f;
  1931.         char *p,*hold_s;
  1932.         int ret,hold_i,hold = 0;
  1933.   
  1934.         if((p = strchr(buf,'<')) != NULLCHAR) {
  1935.             hold = 1;
  1936.             hold_i = mp->pointer;
  1937.             hold_s = mp->path;
  1938.             mp->path = NULLCHAR;
  1939.             if((ret = retr_by_mid(p,mp)) != 0)
  1940.                 return ret;
  1941.         }
  1942.         else if((ret = retr_by_num(buf,mp)) != 0)
  1943.             return ret;
  1944.   
  1945.         if (get_id(mp->buf,mp) != 1)
  1946.             return 1;
  1947.   
  1948.         f = NULL; /* WG7J */
  1949.         if ((f = open_message(mp,f)) == NULLFILE)
  1950.             return -1;
  1951.   
  1952.         usprintf(mp->s,head,mp->pointer,mp->buf,artmsg);
  1953.         while(fgets(mp->buf,LineLen-1,f) != NULLCHAR) {
  1954.             if(check_blank(mp->buf))
  1955.                 break;
  1956.             usputs(mp->s,mp->buf);
  1957.         }
  1958.         usputs(mp->s,NEol);
  1959.   
  1960.         if(hold) {
  1961.             mp->pointer = hold_i;
  1962.             free(mp->path);
  1963.             mp->path = hold_s;
  1964.         }
  1965.         fclose(f);
  1966.         return 0;
  1967.     }
  1968.   
  1969.   
  1970. /*
  1971.  * Do BODY command. Return: success 0, no article 1, error -1.
  1972.  */
  1973.   
  1974.     static int
  1975.     dobodycmd(buf,mp)
  1976.     char *buf;
  1977.     struct nntpsv *mp;
  1978.     {
  1979.         FILE *f;
  1980.         char *p,*hold_s;
  1981.         int ret,hold_i,hold = 0, got;
  1982.   
  1983.         if((p = strchr(buf,'<')) != NULLCHAR) {
  1984.             hold = 1;
  1985.             hold_i = mp->pointer;
  1986.             hold_s = mp->path;
  1987.             mp->path = NULLCHAR;
  1988.             if((ret = retr_by_mid(p,mp)) != 0)
  1989.                 return ret;
  1990.         }
  1991.         else if((ret = retr_by_num(buf,mp)) != 0)
  1992.             return ret;
  1993.   
  1994.         if (get_id(mp->buf,mp) != 1)
  1995.             return 1;
  1996.   
  1997.         f = NULL; /* WG7J */
  1998.         if ((f = open_message(mp,f)) == NULLFILE)
  1999.             return -1;
  2000.   
  2001.         usprintf(mp->s,body,mp->pointer,mp->buf,artmsg);
  2002.         got = 0;
  2003.         while(fgets(mp->buf,LineLen-1,f) != NULLCHAR) {
  2004.             if(got)
  2005.                 usputs(mp->s,mp->buf);
  2006.             if(check_blank(mp->buf))
  2007.                 got = 1;
  2008.         }
  2009.         usputs(mp->s,NEol);
  2010.   
  2011.         if(hold) {
  2012.             mp->pointer = hold_i;
  2013.             free(mp->path);
  2014.             mp->path = hold_s;
  2015.         }
  2016.         fclose(f);
  2017.         return 0;
  2018.     }
  2019.   
  2020.   
  2021. /*
  2022.  * Do STAT command. Return: success 0, no article 1, error -1.
  2023.  */
  2024.   
  2025.     static int
  2026.     dostatcmd(buf,mp)
  2027.     char *buf;
  2028.     struct nntpsv *mp;
  2029.     {
  2030.         char *p,*hold_s;
  2031.         int ret,hold_i,hold = 0;
  2032.   
  2033.         if((p = strchr(buf,'<')) != NULLCHAR) {
  2034.             hold = 1;
  2035.             hold_i = mp->pointer;
  2036.             hold_s = mp->path;
  2037.             mp->path = NULLCHAR;
  2038.             if((ret = retr_by_mid(p,mp)) != 0)
  2039.                 return ret;
  2040.         }
  2041.         else if((ret = retr_by_num(buf,mp)) != 0)
  2042.             return ret;
  2043.   
  2044.         if (get_id(mp->buf,mp) != 1)
  2045.             return 1;
  2046.   
  2047.         usprintf(mp->s,statistics,mp->pointer,mp->buf,artmsg);
  2048.   
  2049.         if(hold) {
  2050.             mp->pointer = hold_i;
  2051.             free(mp->path);
  2052.             mp->path = hold_s;
  2053.         }
  2054.         return 0;
  2055.     }
  2056.   
  2057.   
  2058. /*
  2059.  * Do XHDR command. Return: success 0, no article 1, error -1.
  2060.  */
  2061.   
  2062.     static int
  2063.     doxhdrcmd(buf,mp)
  2064.     char *buf;
  2065.     struct nntpsv *mp;
  2066.     {
  2067.         FILE *f;
  2068.         char *path,*fld,*p,*mid,line[LineLen];
  2069.         int pointer,start,stop,ret = 0;
  2070.   
  2071.         if((fld = strchr(buf,' ')) == NULLCHAR || check_blank(fld)) {
  2072.             usputs(mp->s,badsyntax);
  2073.             return -1;
  2074.         }
  2075.         while(isspace(*++fld));
  2076.   
  2077.         pointer = start = stop = mp->pointer;
  2078.         path = mp->path;
  2079.         mid = mp->path = NULLCHAR;
  2080.   
  2081.         if((p = strchr(fld,' ')) != NULLCHAR && !check_blank(p)) {
  2082.             *p = '\0';
  2083.             while(isspace(*++p));
  2084.   
  2085.             if(*p == '<') {
  2086.                 if((ret = retr_by_mid(p,mp)) != 0)
  2087.                     goto quit;
  2088.                 start = stop = mp->pointer;
  2089.                 mid = p;
  2090.             } else {
  2091.                 start = stop = atoi(p);
  2092.                 if((p = strchr(p,'-')) != NULLCHAR)
  2093.                     stop = atoi(++p);
  2094.             }
  2095.         }
  2096.   
  2097.         if(!mid) {
  2098.             mp->path = strdup(path);
  2099.             if(check_grp(mp)) {
  2100.                 ret = 1;
  2101.                 goto quit;
  2102.             }
  2103.             usprintf(mp->s,xheader1,fld);
  2104.         } else
  2105.             usprintf(mp->s,xheader2,0,fld,p);
  2106.   
  2107.         while(start <= stop) {
  2108.             if(mid || (start >= mp->first && start <= mp->last)) {
  2109.                 sprintf(line,"%s/%u",mp->path,start);
  2110.   
  2111.                 if((f = open_file(line,READ_TEXT,0,0)) != NULLFILE) {
  2112.                     for(;;) {
  2113.                         if(fgets(line,LineLen-1,f) == NULLCHAR
  2114.                         || check_blank(line)) {    /* no match was found */
  2115.                             if(mid)
  2116.                                 usprintf(mp->s,"%s (none)\n",mid);
  2117.                             else
  2118.                                 usprintf(mp->s,"%d (none)\n",start);
  2119.                             break;
  2120.                         }
  2121.   
  2122.                         if((p = strchr(line,':')) != NULLCHAR)
  2123.                             *p = '\0';
  2124.                         if(stricmp(line,fld) == 0) {
  2125.                             if(mid)
  2126.                                 usprintf(mp->s,"%s %s",mid,p + 2);
  2127.                             else
  2128.                                 usprintf(mp->s,"%d %s",start,p + 2);
  2129.                             break;
  2130.                         }
  2131.                     }
  2132.                     fclose(f);
  2133.                 }
  2134.             }
  2135.             start++;
  2136.         }
  2137.         usputs(mp->s,NEol);
  2138.   
  2139.         quit:
  2140.         mp->pointer = pointer;
  2141.         free(mp->path);
  2142.         mp->path = path;
  2143.   
  2144.         return ret;
  2145.     }
  2146.   
  2147. /*
  2148.  * Do XOVER command. Return: success 0, error -1.
  2149.  */
  2150.   
  2151.     static int
  2152.     doxovercmd(buf,mp)
  2153.     char *buf;
  2154.     struct nntpsv *mp;
  2155.     {
  2156.         FILE *f;
  2157.         char *subject,*from,*date,*mid,*ref,*xref,*p,line[LineLen];
  2158.         int lines,size,start,stop,got;
  2159.   
  2160.         if((p = strchr(buf,' ')) != NULLCHAR) {
  2161.             start = stop = atoi(p);
  2162.             if((p = strchr(buf,'-')) != NULLCHAR)
  2163.                 stop = atoi(++p);
  2164.         } else
  2165.             start = stop = mp->pointer;
  2166.   
  2167.         usputs(mp->s,xover);
  2168.   
  2169.         while(start <= stop) {
  2170.             if(start >= mp->first && start <= mp->last) {
  2171.                 sprintf(line,"%s/%u",mp->path,start);
  2172.                 if((f = open_file(line,READ_TEXT,0,0)) != NULLFILE) {
  2173.                     subject = from = date = mid = ref = xref = NULLCHAR;
  2174.                     lines = size = got = 0;
  2175.                     while(fgets(line,LineLen-1,f) != NULLCHAR) {
  2176.                         rip2(line);
  2177.                         if(got == 0) {
  2178.                             if(strnicmp(line,subj,9) == 0)
  2179.                                 subject = strdup(strchr(line,' ') + 1);
  2180.                             else if(strnicmp(line,frm,6) == 0)
  2181.                                 from = strdup(strchr(line,' ') + 1);
  2182.                             else if(strnicmp(line,dte,6) == 0)
  2183.                                 date = strdup(strchr(line,' ') + 1);
  2184.                             else if(strnicmp(line,msgid,12) == 0)
  2185.                                 mid = strdup(strchr(line,' ') + 1);
  2186.                             else if(strnicmp(line,"Lines: ",7) == 0)
  2187.                                 lines = atoi(strchr(line,' ') + 1);
  2188.                             else if(strnicmp(line,"References: ",12) == 0)
  2189.                                 ref = strdup(strchr(line,' ') + 1);
  2190.                         } else
  2191.                             size += strlen(line);
  2192.                         if(*line == '\0')
  2193.                             got = 1;
  2194.                     }
  2195.                     usprintf(mp->s,"%u\t%s\t%s\t%s\t%s\t%s\t%u\t%u\t%s\n",
  2196.                     start,subject,from,date,mid, /* these must be present */
  2197.                     ref ? ref : "",
  2198.                     size,lines,
  2199.                     "");              /* last field not (yet) implemented */
  2200.   
  2201.                     free(subject);
  2202.                     free(from);
  2203.                     free(date);
  2204.                     free(mid);
  2205.                     free(ref);
  2206.                     fclose(f);
  2207.                 }
  2208.             }
  2209.             start++;
  2210.         }
  2211.         usputs(mp->s,NEol);
  2212.         return 0;
  2213.     }
  2214.   
  2215.   
  2216. /* Checks and rewrites message headers if needed. Returns -1 if error,
  2217.  * 0 if all RFC1036 headers are present and 1 if a subset of RFC1036
  2218.  * headers is present. (1 means that IHAVE should be rejected but
  2219.  * POST is ok.)
  2220.  */
  2221.   
  2222.     static int
  2223.     garbled(inf,outf)
  2224.     FILE *inf;
  2225.     FILE *outf;
  2226.     {
  2227.         char line[LineLen],*cp;
  2228.         int got,ok,lines,ret;
  2229.         long currtime;
  2230.   
  2231.         got = ok = lines = 0;
  2232.   
  2233.     /* first scan the headers */
  2234.         rewind(inf);
  2235.         while(fgets(line,LineLen,inf) != NULLCHAR) {
  2236.             if(got) {
  2237.                 lines++;
  2238.                 continue;
  2239.             }
  2240.             rip2(line);
  2241.             if (check_blank(line)) {                        /* end of headers */
  2242.                 got = 1;
  2243.                 continue;
  2244.             }
  2245.   
  2246.             if (line[0] == ' ' || line[0] == '\t')     /* continuation header */
  2247.                 continue;
  2248.   
  2249.             cp = line;
  2250.             while (*cp != '\0' && *cp != ' ' && *cp != ':')
  2251.                 cp++;
  2252.             if (*cp != ':' || *++cp != ' ')
  2253.                 return -1;                      /* bad header; reject article */
  2254.   
  2255.             cp++;
  2256.             if (check_blank(cp))                              /* empty header */
  2257.                 continue;
  2258.   
  2259.             if (!strnicmp(line,frm,6))
  2260.                 ok |= 1;
  2261.             if (!strnicmp(line,subj,9))
  2262.                 ok |= 2;
  2263.             if (!strnicmp(line,ngrps,12))
  2264.                 ok |= 4;
  2265.             if (!strnicmp(line,dte,6))
  2266.                 ok |= 8;
  2267.             if (!strnicmp(line,msgid,12))
  2268.                 if (check_article(cp) == 0)
  2269.                     ok |= 16;
  2270.             if (!strnicmp(line,pth,6))
  2271.                 ok |= 32;
  2272.             if (!strnicmp(line,"Lines: ",7))
  2273.                 ok |= 64;
  2274.         }
  2275.   
  2276.         if((ok & 7) != 7)           /* From, Subject and Newsgroups not found */
  2277.             return -1;
  2278.   
  2279.         if(ok == 63)
  2280.             ret = 0;                                         /* everything ok */
  2281.         else
  2282.             ret = 1;
  2283.   
  2284.     /* then rewrite if necessary */
  2285.         got = 0;
  2286.         rewind(inf);
  2287.         while(fgets(line,LineLen,inf) != NULLCHAR) {
  2288.             pwait(NULL);
  2289.             if(got) {
  2290.                 fputs(line,outf);
  2291.                 continue;
  2292.             }
  2293.             if(check_blank(line)) {
  2294.                 got = 1;
  2295.                 if(!(ok & 64))
  2296.                     fprintf(outf,"Lines: %d\n\n",lines);
  2297.                 continue;
  2298.             }
  2299.   
  2300.             if(line[0] != ' ' && line[0] != '\t') {
  2301.                 cp = strchr(line,':');
  2302.                 cp++;
  2303.                 if(check_blank(cp))              /* empty header; do not copy */
  2304.                     continue;
  2305.             }
  2306.             if(!strnicmp(line,"Xref: ",6) ||
  2307.                 !strnicmp(line,"Date-Received: ",15) ||
  2308.                 !strnicmp(line,"Posted: ",8) ||
  2309.                 !strnicmp(line,"Posting-Version: ",17) ||
  2310.                 !strnicmp(line,"Received: ",10) ||
  2311.                 !strnicmp(line,"Relay-Version: ",15))
  2312.                 continue;                        /* do not copy these headers */
  2313.   
  2314.             fputs(line,outf);
  2315.             rip2(line);
  2316.   
  2317.         /* no path? */
  2318.             if (!(ok & 32) && strnicmp(line,frm,6) == 0) {
  2319.                 fprintf(outf,"%snot-for-mail\n",pth);
  2320.                 ok |= 32;
  2321.             }
  2322.   
  2323.             if (strnicmp(line,subj,9) == 0) {
  2324.             /* no msgid? */
  2325.                 if (!(ok & 16)) {
  2326.                     fprintf(outf,"%s<%ld@%s>\n",msgid,get_msgid(),Hostname);
  2327.                     ok |= 16;
  2328.                 }
  2329.             /* no date? */
  2330.                 if (!(ok & 8)) {
  2331.                     time(&currtime);
  2332.                     fprintf(outf,"%s%s",dte,ptime(&currtime));
  2333.                     ok |= 8;
  2334.                 }
  2335.             }
  2336.         }
  2337.   
  2338.         rewind(outf);
  2339.         return ret;
  2340.     }
  2341.   
  2342.   
  2343.   
  2344. /* returncode: -1 if error; 0 success */
  2345.   
  2346.     static int
  2347.     get_article2(mp, id)
  2348.     struct nntpsv *mp;
  2349.     char *id;
  2350.     {
  2351.         FILE *f,*f1;
  2352.         int ret = -1;
  2353.   
  2354.         if((f = temp_file(0,1)) == NULLFILE)
  2355.             return -1;
  2356.         if((f1 = temp_file(0,1)) == NULLFILE) {
  2357.             fclose(f);
  2358.             return -1;
  2359.         }
  2360.   
  2361.         mp->ap = (struct article *)callocw(1,sizeof(struct article));
  2362.         mp->id = (*id) ? strdup(id) : strdup(">");
  2363.         usputs(mp->s,sendart);
  2364.   
  2365.         if(recv_file(f,mp->s) == (-1)) {
  2366.             free((struct article *)mp->ap);
  2367.             goto quit;
  2368.         }
  2369.   
  2370.         if (garbled(f,f1) != 0) {
  2371.             usputs(mp->s,transnotok);
  2372.             free((struct article *)mp->ap);
  2373.             goto quit;
  2374.         }
  2375.   
  2376.         if(xfer_article2(f1,mp) < 1)
  2377.             usputs(mp->s,transnotok);
  2378.         else {
  2379.             ret = 0;
  2380.             usputs(mp->s,transok);
  2381.         }
  2382.   
  2383.         quit:
  2384.   
  2385.         fclose(f);
  2386.         fclose(f1);
  2387.         return ret;
  2388.     }
  2389.   
  2390. /*
  2391.  * Do a POST -command. Returns 0 if success.
  2392.  */
  2393.   
  2394.     static int
  2395.     post_article(mp)
  2396.     struct nntpsv *mp;
  2397.     {
  2398.         FILE *f,*f1;
  2399.         int ret = -1;
  2400.         char *p,*p1;
  2401.   
  2402.         if((f = temp_file(0,1)) == NULLFILE)
  2403.             return -1;
  2404.         if((f1 = temp_file(0,1)) == NULLFILE) {
  2405.             fclose(f);
  2406.             return -1;
  2407.         }
  2408.   
  2409.         usputs(mp->s,sendpost);
  2410.   
  2411.         if(recv_file(f,mp->s) == (-1))
  2412.             goto quit;
  2413.   
  2414.         if (garbled(f,f1) < 0) {
  2415.             usprintf(mp->s,"%s - header garbled\n",postfailed);
  2416.             goto quit;
  2417.         }
  2418.   
  2419.         rewind(f1);
  2420.         while (fgets(mp->buf,LineLen,f1) != NULL) {
  2421.             rip2(mp->buf);
  2422.             if (strnicmp(mp->buf,msgid,12) == 0) {
  2423.                 mp->id = strdup((strchr(mp->buf,' ')) + 1);
  2424.                 break;
  2425.             }
  2426.         }
  2427.   
  2428.         rewind(f1);
  2429.         if(xfer_article2(f1,mp) < 1)
  2430.             usprintf(mp->s,"%s\n",postfailed);
  2431.         else
  2432.             usputs(mp->s,postok);
  2433.   
  2434.         quit:
  2435.   
  2436.         fclose(f1);
  2437.         fclose(f);
  2438.         return 0;
  2439.     }
  2440.   
  2441.   
  2442.     void
  2443.     poll(p)
  2444.     void *p;
  2445.     {
  2446.   
  2447.         if (newproc("NNTP Client", 2048, nntppoll, 0, p, NULL, 0) == NULLPROC)
  2448.             start_timer(&((struct Servers *)p)->nntpt);    /* N5KNX: retry later */
  2449.  
  2450.     }
  2451.   
  2452.   
  2453.     static int
  2454.     chk_access(s)
  2455.     int s;
  2456.     {
  2457.         struct sockaddr fsocket;
  2458.         FILE *f;
  2459.         int trans,verb,i;
  2460.         int access = -1;                            /* default is no access */
  2461.         char *cp,*cp1,name[80], line[80];
  2462.   
  2463.         trans = DTranslate;                           /* save the old state */
  2464.         verb = DVerbose;
  2465.         DTranslate = 1;      /* force the output of psocket() to be literal */
  2466.         DVerbose = 1;
  2467.         i = SOCKSIZE;
  2468.   
  2469.         if(getpeername(s,(char *)&fsocket,&i) != -1) {
  2470.             strcpy(name,psocket(&fsocket));
  2471.             if((cp = strchr(name,':')) != NULLCHAR)
  2472.                 *cp = '\0';
  2473.         }
  2474.   
  2475.         DTranslate = trans;                        /* restore the old state */
  2476.         DVerbose = verb;
  2477.   
  2478.         if((f = open_file(Naccess,READ_TEXT,s,0)) != NULLFILE) {
  2479.             while(fgets(line,79,f) != NULLCHAR) {
  2480.                 if(*line == '#')
  2481.                     continue;
  2482.                 if((cp = strchr(line,':')) != NULLCHAR)
  2483.                     *cp = '\0';
  2484.                 if(wildmat(name,line,NULLCHARP)) {
  2485.                     if((cp1 = strchr(++cp,':')) != NULLCHAR)
  2486.                         *cp1 = '\0';
  2487.                     if(strchr(cp,'R'))                         /* read only */
  2488.                         access = 0;
  2489.                     if(strchr(cp,'P'))                     /* read and post */
  2490.                         access = 1;
  2491.                     break;
  2492.                 }
  2493.             }
  2494.             fclose(f);
  2495.         }
  2496.         return access;
  2497.     }
  2498.   
  2499.     static void
  2500.     nntpserv(s,unused,p)
  2501.     int s;
  2502.     void *unused;
  2503.     void *p;
  2504.     {
  2505.         struct nntpsv *mp;
  2506.         FILE *fp;
  2507.         long t;
  2508.         int cnt, postallowed = 1;
  2509.         char **cmdp, *arg, *cp, *cmd, buf[LineLen];
  2510.   
  2511. #ifdef LZW
  2512.         int lbits, lmode;
  2513. #endif
  2514.   
  2515.         sockmode(s,SOCK_ASCII);
  2516.         sockowner(s,Curproc);           /* We own it now */
  2517.         log(s,"open NNTP");
  2518.   
  2519.         if (!Filecheck)
  2520.             if(check_system()) {
  2521.                 usprintf(s,fatal,"STRUCTURE");
  2522.                 log(s,"NNTP error - FILE STRU");
  2523.                 close_s(s);
  2524.                 return;
  2525.             }
  2526.   
  2527.         if((mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
  2528.             usputs(s,Nospace);
  2529.             close_s(s);
  2530.             return;
  2531.         }
  2532.   
  2533.         if(Nntpaccess)
  2534.             if((postallowed = chk_access(s)) < 0) {
  2535.                 usputs(s,noaccess);
  2536.                 close_s(s);
  2537.                 return;
  2538.             }
  2539.   
  2540.         mp->s = s;
  2541.         mp->debug = 0;
  2542.         mp->path = NULLCHAR;
  2543.   
  2544.         time(&t);
  2545.         cp = ctime(&t);
  2546.         cp[24] = '\0';
  2547.   
  2548.         usprintf(s,nnversion,postallowed ? "0" : "1",Host,Version,cp,
  2549.         postallowed ? "(posting ok)" : "(no posting)");
  2550.   
  2551.         loop:
  2552.   
  2553.         if ((cnt = recvline(s,buf,LineLen)) == -1) {
  2554.         /* He closed on us */
  2555.             goto quit;
  2556.   
  2557.         }
  2558.   
  2559.         if(check_blank(buf))
  2560.             goto loop;        /* empty line, do nothing */
  2561.   
  2562.         rip2(buf);
  2563.         cmd = buf;
  2564.   
  2565.     /* Translate entire buffer to lower case */
  2566.   
  2567.         for(cp = cmd; *cp != '\0' ;cp++) {
  2568.             if ( *cp == ' ' ) break;
  2569.             *cp = tolower(*cp);
  2570.         }
  2571.   
  2572.     /* Find command in table; if not present, return syntax error */
  2573.     /* If not present, return 500 command unrecognized */
  2574.   
  2575.         for(cmdp = commands; *cmdp != NULLCHAR; cmdp++)
  2576.             if(strnicmp(*cmdp,cmd,min(strlen(*cmdp),strlen(cmd))) == 0)
  2577.                 break;
  2578.   
  2579.         if(*cmdp == NULLCHAR){
  2580.             usputs(mp->s,notrecognd);
  2581.             goto loop;
  2582.         }
  2583.   
  2584.         arg = &cmd[strlen(*cmdp)];
  2585.   
  2586.     /* Skip spaces after command */
  2587.   
  2588.         while(*arg == ' ')
  2589.             arg++;
  2590.   
  2591.     /* Execute specific command */
  2592.   
  2593.         switch(cmdp - commands) {
  2594.   
  2595.             case XLZW_CMD:
  2596.   
  2597. #ifdef LZW
  2598.                 if (LzwActive)   {
  2599.                     usputs(mp->s,transok);
  2600.                     cp = strchr(arg,' ');
  2601.                     *cp++ = '\0';
  2602.                     lbits = atoi(arg); /*get lzwbits*/
  2603.                     lmode = atoi(cp);
  2604.                     lzwinit(mp->s,lbits,lmode);
  2605.                 } else
  2606. #endif
  2607.                     usputs(mp->s,error);
  2608.   
  2609.                 break;
  2610.   
  2611.             case QUIT_CMD:
  2612.   
  2613.                 goto quit;
  2614.   
  2615.             case NEWNEWS_CMD:
  2616.   
  2617.                 if ((cp = strchr(buf,' ')) == NULLCHAR) {
  2618.                     usputs(mp->s,badsyntax);
  2619.                     break;
  2620.                 }
  2621.   
  2622.                 cp++;
  2623.                 donewnews(cp,mp);
  2624.                 break;
  2625.   
  2626.             case IHAVE_CMD:
  2627.   
  2628.                 if ((cp = strchr(buf,'<')) == NULLCHAR) {
  2629.                     usputs(mp->s,badsyntax);
  2630.                     break;
  2631.                 }
  2632.   
  2633.                 if (check_article(cp) != 0) {
  2634.                     usputs(mp->s,notwanted);
  2635.                     break;
  2636.                 }
  2637.   
  2638.                 if(get_article2(mp,cp))
  2639.                     goto quit;
  2640.   
  2641.                 break;
  2642.   
  2643.             case POST_CMD:
  2644.   
  2645.                 if (!postallowed) {
  2646.                     usputs(mp->s,notallowed);
  2647.                     break;
  2648.                 }
  2649.   
  2650.                 post_article(mp);
  2651.                 break;
  2652.   
  2653.             case HELP_CMD:
  2654.   
  2655.                 usprintf(mp->s,"100 %s - help follows:\n",Host);
  2656.   
  2657.                 if ((fp = open_file(Nhelp,READ_TEXT,0,0)) != NULLFILE ) {
  2658.                     sendfile(fp,mp->s,ASCII_TYPE,0,NULL);
  2659.                     fclose(fp);
  2660.                 } else {
  2661.                     usprintf(mp->s,"\nKA9Q NOS NNTP Server, version %s\n\n",Version);
  2662.                     for(cnt = 1;commands[cnt] != NULLCHAR;cnt++)
  2663.                         usprintf(mp->s,"%-9s%c",commands[cnt],(cnt%7) ? ' ' : '\n');
  2664.                     usputs(mp->s,"\n");
  2665.                 }
  2666.   
  2667.                 usputs(mp->s,NEol);
  2668.                 break;
  2669.   
  2670.             case XINFO_CMD:
  2671.   
  2672.                 if ((fp = open_file(NInfo,READ_TEXT,0,0)) != NULLFILE ) {
  2673.                     usprintf(mp->s,"100 %s - xinfo follows:\n",Host);
  2674.                     sendfile(fp,mp->s,ASCII_TYPE,0,NULL);
  2675.                     fclose(fp);
  2676.                 } else {
  2677.                     usputs(mp->s,xinfo);
  2678.                 }
  2679.   
  2680.                 usputs(mp->s,NEol);
  2681.                 break;
  2682.   
  2683.             case LIST_CMD:
  2684.   
  2685.                 if ((fp = open_file(Active,READ_TEXT,mp->s,0)) != NULLFILE) {
  2686.                     usputs(mp->s,listgroups);
  2687.                     sendfile(fp,mp->s,ASCII_TYPE,0,NULL);
  2688.                     fclose(fp);
  2689.                     usputs(mp->s,NEol);
  2690.                 }
  2691.                 break;
  2692.   
  2693.             case NEWGROUPS_CMD:
  2694.  
  2695.                 usputs(mp->s, newgroups);
  2696.                 usputs(mp->s, NEol);      /* empty list, as it's NOT IMPLEMENTED */
  2697.                 break;
  2698.  
  2699.             case GROUP_CMD :
  2700.   
  2701.                 dogroup(mp,buf);
  2702.                 break;
  2703.   
  2704.             case HEAD_CMD :
  2705.   
  2706.                 doheadcmd(buf,mp);
  2707.                 break;
  2708.   
  2709.             case BODY_CMD :
  2710.   
  2711.                 dobodycmd(buf,mp);
  2712.                 break;
  2713.   
  2714.             case STAT_CMD :
  2715.   
  2716.                 dostatcmd(buf,mp);
  2717.                 break;
  2718.   
  2719.             case ARTICLE_CMD :
  2720.   
  2721.                 doarticlecmd(buf,mp);
  2722.                 break;
  2723.   
  2724.             case XHDR_CMD :
  2725.   
  2726.                 doxhdrcmd(buf,mp);
  2727.                 break;
  2728.   
  2729.             case XOVER_CMD :
  2730.   
  2731.                 if (check_grp(mp))
  2732.                     break;
  2733.   
  2734.                 doxovercmd(buf,mp);
  2735.                 break;
  2736.   
  2737.             case NEXT_CMD :
  2738.   
  2739.                 if (check_grp(mp))
  2740.                     break;
  2741.   
  2742.                 if (get_next(mp) == 1) {
  2743.                     if (get_id(buf,mp) == 1)
  2744.                         usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
  2745.                     break;
  2746.                 }
  2747.   
  2748.                 break;
  2749.   
  2750.             case LAST_CMD :
  2751.   
  2752.                 if (check_grp(mp))
  2753.                     break;
  2754.   
  2755.                 if (get_last(mp) == 1 ) {
  2756.                     if (get_id(buf,mp) == 1)
  2757.                         usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
  2758.                     break;
  2759.                 }
  2760.   
  2761.                 break;
  2762.   
  2763.     /* This two following cmds currently are not used for much */
  2764.   
  2765.             case DEBUG_CMD:
  2766.   
  2767.                 mp->debug = (mp->debug == 0) ? 1 : 0;
  2768.                 usprintf(mp->s,debug,(mp->debug == 0) ? "OFF" : "ON");
  2769.                 break;
  2770.   
  2771.             case SLAVE_CMD :
  2772.   
  2773.                 mp->slave = (mp->slave == 0) ? 1 : 0;
  2774.                 usprintf(mp->s,slave,(mp->slave == 0) ? "OFF" : "ON");
  2775.                 break;
  2776.   
  2777.         }
  2778.   
  2779.         goto loop;
  2780.   
  2781.   
  2782.         quit:
  2783.   
  2784.         usputs(mp->s,closing);
  2785.         log(mp->s,"close NNTP");
  2786.         close_s(mp->s);
  2787.   
  2788.         if(mp->path != NULLCHAR)
  2789.             free(mp->path);
  2790.   
  2791.         if(mp->newnews != NULLCHAR)
  2792.             free(mp->newnews);
  2793.   
  2794.         if(mp->fname != NULLCHAR)
  2795.             free(mp->fname);
  2796.   
  2797.         if(mp->id != NULLCHAR);
  2798.         free(mp->id);
  2799.   
  2800.         free((char *)mp);
  2801.     }
  2802.   
  2803.   
  2804.   
  2805. /* ---------------------------- NNTP-GATE --------------------------- */
  2806.   
  2807.   
  2808.   
  2809.     static char * near
  2810.     mkreplypath(FILE *data)
  2811.     {
  2812.         char buf[LineLen], *cp, *cp1, *path;
  2813.   
  2814.         sprintf(buf,"%sNNTP_GATE@%s",pth,Hostname);
  2815.         path = strdup(buf);
  2816.         rewind(data);
  2817.   
  2818.         while((fgets(buf,LineLen,data)) != 0) {
  2819.             if(htype(buf) == DATE)
  2820.                 break;
  2821.   
  2822.             if(htype(buf) == RECEIVED) {
  2823.                 cp = strchr(buf,' ');
  2824.                 cp++;
  2825.                 cp = strchr(cp, ' ');
  2826.                 cp++;
  2827.                 cp1 = strpbrk(cp, ". \0");
  2828.                 *cp1 = '\0';
  2829.                 cp1 = mallocw(strlen(path)+strlen(cp)+2);  /* */
  2830.                 sprintf(cp1,"%s!%s",path,cp);
  2831.                 free(path);
  2832.                 path = cp1;
  2833.             }
  2834.         }
  2835.         return(path);
  2836.     }
  2837.   
  2838.   
  2839.     int
  2840.     nnGpost(FILE *data,char *from,struct list *le)
  2841.     {
  2842.         struct nntpsv *mp;
  2843.         char buf[LineLen], *cp;
  2844.         FILE *f, *idf;
  2845.         int32 id;
  2846.         int strl;
  2847.         long currtime;
  2848.   
  2849.         if (!Filecheck)
  2850.             if(check_system())
  2851.                 return -1;
  2852.   
  2853.         if ((f = temp_file(0,1)) == NULLFILE)
  2854.             return -1;
  2855.   
  2856.         mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
  2857.   
  2858.     /* build postuser */
  2859.   
  2860.         cp = mkreplypath(data);
  2861.         fprintf(f,"%s\n",cp);
  2862.         free((char *)cp);
  2863.         fprintf(f,"%s%s\n",frm,from);
  2864.   
  2865.    /*-----------------------------------------------------------------*
  2866.     * build newsgroup                                                 *
  2867.     *-----------------------------------------------------------------*/
  2868.   
  2869.         if((cp = strchr(le->val,'@')) != NULLCHAR)
  2870.             *cp = '\0';
  2871.   
  2872.         strcpy(buf,le->val);
  2873.         cp=buf;
  2874.         strl = strlen(cp);
  2875.   
  2876.         while(*cp != '\0') {
  2877.             if(*cp == '!') *cp = '.'; /* change ! into . - yc1dav */
  2878.             cp++;
  2879.         }
  2880.   
  2881.         fprintf(f,"%s%s\n",ngrps,(cp-strl+1));  /* skip the first "." */
  2882.   
  2883.    /*-----------------------------------------------------------------*
  2884.     * find the subject
  2885.     *-----------------------------------------------------------------*/
  2886.   
  2887.         rewind (data);
  2888.         while((fgets(buf,sizeof(buf),data))!=0)   {
  2889.             if (htype(buf)== SUBJECT)
  2890.                 break;
  2891.   
  2892.             continue;
  2893.         }
  2894.   
  2895.         fputs((*buf == 0) ? "Subject: (none)\n" : buf,f);
  2896.   
  2897.    /*--------------------------------------------------------------------*
  2898.     * use msgid of original message
  2899.     *--------------------------------------------------------------------*/
  2900.   
  2901.         rewind(data);
  2902.   
  2903.         while((fgets(buf,sizeof(buf),data))!=0)   {
  2904.             if (htype(buf)== MSGID)
  2905.                 break;
  2906.   
  2907.             continue;
  2908.         }
  2909.   
  2910.         if (*buf == 0)   {
  2911.             sprintf(buf,"%s/sequence.seq",Mailqdir);
  2912.             idf = open_file(buf,"r+",0,1);
  2913.             id = atol(fgets(buf,LineLen,idf));
  2914.             rewind(idf);
  2915.             fprintf(idf,"%ld",id+1);
  2916.             fclose(idf);
  2917.             fprintf(f,"%s<%ld@%s>\n",msgid,id,Hostname);
  2918.             sprintf(mp->buf,"<%ld@%s>",id,Hostname);
  2919.         } else {
  2920.             fputs(buf,f);
  2921.             rip(buf);
  2922.             cp = strchr(buf,'<');
  2923.             strcpy(mp->buf,cp);
  2924.   
  2925.             if (check_article(mp->buf))
  2926.                 goto quit;
  2927.         }
  2928.   
  2929.         rewind (data);
  2930.         time(&currtime);
  2931.         fprintf(f,"Sender: NNTP@%s\n",Hostname);
  2932.   
  2933.    /*--------------------------------------------------------------------*
  2934.     * message follows                                                    *
  2935.     *--------------------------------------------------------------------*/
  2936.   
  2937.         fputs("Comments: Message transferred from SMTP\n",f);
  2938.         while((fgets(buf,sizeof(buf),data))!=0)   {
  2939.             switch(htype(buf))   {
  2940.   
  2941.                 case FROM:
  2942.   
  2943.                 case MSGID:
  2944.   
  2945.                 case RECEIVED:
  2946.   
  2947.                     fgets(buf,sizeof(buf),data); /*eat the id*/
  2948.                     continue;
  2949.             }
  2950.   
  2951.             fputs(buf,f);
  2952.         }
  2953.   
  2954.         rewind(f);
  2955.         mp->id = strdup(mp->buf);
  2956.         xfer_article2(f,mp);
  2957.   
  2958. /*
  2959.  *
  2960.  *  log(-1,"NNGT: transfer: Msg %s",mp->id);
  2961.  *
  2962.  */
  2963.   
  2964.         quit:
  2965.   
  2966.         fclose(f);
  2967.         free(mp);
  2968.         return 0;
  2969.     }
  2970.   
  2971.   
  2972.   
  2973. /* ---------------------------- Servercmd --------------------------- */
  2974.   
  2975.   
  2976.   
  2977. /* Start up NNTP receiver service */
  2978.     int
  2979.     nntp1(argc,argv,p)
  2980.     int argc;
  2981.     char *argv[];
  2982.     void *p;
  2983.     {
  2984.         int16 port;
  2985.   
  2986.         if(check_system() == -1)
  2987.             return -1;
  2988.   
  2989.         if(argc < 2)
  2990.             port = IPPORT_NNTP;
  2991.         else
  2992.             port = atoi(argv[1]);
  2993.   
  2994.         return start_tcp(port,"NNTP Server",nntpserv,2048);
  2995.     }
  2996.   
  2997. /* Shutdown NNTP service (existing connections are allowed to finish) */
  2998.     int
  2999.     nntp0(argc,argv,p)
  3000.     int argc;
  3001.     char *argv[];
  3002.     void *p;
  3003.     {
  3004.         int16 port;
  3005.   
  3006.         if(argc < 2)
  3007.             port = IPPORT_NNTP;
  3008.         else
  3009.             port = atoi(argv[1]);
  3010.         return stop_tcp(port);
  3011.     }
  3012.   
  3013. /* ---------------------------- Subcmds --------------------------- */
  3014. /* lists active newsgroups
  3015.  * returncode: -1 if error; 0 success */
  3016.   
  3017.     static int
  3018.     donnactive(argc,argv,p)
  3019.     int argc;
  3020.     char *argv[];
  3021.     void *p;
  3022.     {
  3023.         FILE *fp;
  3024.         char line[80], *cp;
  3025.   
  3026.         if((fp = open_file(Active,READ_TEXT,0,1)) == NULLFILE)
  3027.             return -1;
  3028.   
  3029.         tputs("Msg#  next  mod newsgroup\n");
  3030.   
  3031.         for(;;) {
  3032.             if (fgets(line,sizeof(line),fp) == NULL)
  3033.                 break;
  3034.             if((cp = strchr(line,' ')) == NULLCHAR)
  3035.                 break;
  3036.             *cp = '\0';
  3037.             rip(++cp);
  3038.             tprintf("%s   %s\n",cp,line);
  3039.             pwait(NULL);
  3040.         }
  3041.         fclose(fp);
  3042.         return 0;
  3043.     }
  3044.   
  3045.   
  3046.     static int
  3047.     donnaccess(argc,argv,p)
  3048.     int argc;
  3049.     char *argv[];
  3050.     void *p;
  3051.     {
  3052.         return setbool(&Nntpaccess,"NNTP access",argc,argv);
  3053.     }
  3054.   
  3055.   
  3056.   
  3057. /* add nntp servers to list */
  3058.     static int
  3059.     donnadds(argc,argv,p)
  3060.     int argc;
  3061.     char *argv[];
  3062.     void *p;
  3063.     {
  3064.         struct Servers *np;
  3065.   
  3066.         for(np = Nntpserver; np != NULLSERVER; np = np->next)
  3067.             if(stricmp(np->name,argv[1]) == 0)
  3068.                 break;
  3069.         if (np == NULLSERVER) {
  3070.             np = (struct Servers *)callocw(1,sizeof(struct Servers));
  3071.             if((np->dest = resolve(argv[1])) == 0) {
  3072.                 tprintf(Badhost,argv[1]);
  3073.                 free((char *)np);
  3074.                 return -1;
  3075.             }
  3076.             np->name = strdup(argv[1]);
  3077.             np->next = Nntpserver;
  3078.             Nntpserver = np;
  3079.             np->newsgroups = NULLCHAR;
  3080.             np->lowtime = np->hightime = -1;
  3081.             np->nntpt.func = poll;          /* what to call on timeout */
  3082.             np->nntpt.arg = (void *)np;
  3083.         }
  3084.  
  3085.         if (argc > 3) {
  3086.             int i;
  3087.             if (np->newsgroups == NULLCHAR) {
  3088.                 np->newsgroups = callocw(1,LineLen);
  3089.                 *np->newsgroups = '\0';
  3090.             }
  3091.  
  3092.             for (i = 3; i < argc; ++i) {
  3093.                 if (isdigit(*argv[i])) {
  3094.                     int lh, ll, hh, hl;
  3095.                     sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
  3096.                     np->lowtime = lh * 100 + ll;
  3097.                     np->hightime = hh * 100 + hl;
  3098.                 } else if ((strlen(np->newsgroups)+strlen(argv[i])+2) >= LineLen)
  3099.                     tprintf("To many groups, '%s' ignored\n", argv[i]);
  3100.                 else {  /* it's a group, and it fits... add it to list */
  3101.                     if (*np->newsgroups != '\0')
  3102.                         strcat(np->newsgroups, ",");
  3103.                     strcat(np->newsgroups, argv[i]);
  3104.                 }
  3105.             }
  3106.  
  3107.             if (*np->newsgroups == '\0') {  /* No groups specified? */
  3108.                 free(np->newsgroups);
  3109.                 np->newsgroups = NULLCHAR;
  3110.             }
  3111.         }
  3112.     /* set timer duration */
  3113.         set_timer(&np->nntpt,atol(argv[2])*1000L);
  3114.         start_timer(&np->nntpt);                /* and fire it up */
  3115.         return 0;
  3116.     }
  3117.   
  3118. static int
  3119. donnfirstpoll(argc,argv,p)    /* from G8FSL */
  3120. int argc;
  3121. char *argv[];
  3122. void *p;
  3123. {
  3124.     return setint(&Nntpfirstpoll,"NNTP polls new server for news over last <n> days",argc,argv);
  3125. }
  3126.  
  3127.   
  3128. /* create a new newsgroup */
  3129.     static int
  3130.     donncreate(argc,argv,p)
  3131.     int argc;
  3132.     char *argv[];
  3133.     void *p;
  3134.     {
  3135.         FILE *f,*t;
  3136.         char line[LineLen];
  3137.         int n;
  3138.   
  3139.         if ((f = open_file(Active,READ_TEXT,0,1)) == NULL)
  3140.             return -1;
  3141.   
  3142.         if ((t = temp_file(0,1)) == NULL) {
  3143.             fclose(f);
  3144.             return -1;
  3145.         }
  3146.   
  3147.         while (fgets(line,LineLen,f) != NULL) {
  3148.             fputs(line,t);
  3149.             n = strcspn(line," ");
  3150.             line[n] = '\0';
  3151.   
  3152.             if (strcmp(line,argv[1]) == 0) {
  3153.                 tprintf("Newsgroup %s already exists.\n",argv[1]);
  3154.                 goto quit;
  3155.             }
  3156.         }
  3157.   
  3158.         rewind(t);
  3159.         fclose(f);
  3160.   
  3161.         if (argc > 2 && *argv[2] == 'n')
  3162.             n = 1;
  3163.         else
  3164.             n = 0;
  3165.   
  3166.         if (!make_path(argv[1])) {
  3167.             if ((f = open_file(Active,WRITE_TEXT,0,1)) == NULL) {
  3168.                 fclose(t);
  3169.                 return -1;
  3170.             }
  3171.   
  3172.             while (fgets(line,LineLen,t) != NULL)
  3173.                 fputs(line,f);
  3174.   
  3175.             fprintf(f,"%s 00000 00001 %c\n",argv[1],(n ? 'n' : 'y'));
  3176.         }
  3177.   
  3178.         quit:
  3179.   
  3180.         fclose(f);
  3181.         fclose(t);
  3182.         return 0;
  3183.     }
  3184.   
  3185.   
  3186. /* drops nntp servers from list */
  3187.   
  3188.     static int
  3189.     donndrops(argc,argv,p)
  3190.     int argc;
  3191.     char *argv[];
  3192.     void *p;
  3193.     {
  3194.         struct Servers *np, *npprev = NULLSERVER;
  3195.   
  3196.         for(np = Nntpserver; np != NULLSERVER; npprev = np, np = np->next)
  3197.             if(stricmp(np->name,argv[1]) == 0) {
  3198.                 stop_timer(&np->nntpt);
  3199.                 free(np->name);
  3200.                 if (np->newsgroups)
  3201.                     free(np->newsgroups);
  3202.                 if(npprev != NULLSERVER)
  3203.                     npprev->next = np->next;
  3204.                 else
  3205.                     Nntpserver = np->next;
  3206.                 free((char *)np);
  3207.                 return 0;
  3208.             }
  3209.         tputs("No such server enabled.\n");
  3210.         return -1;
  3211.     }
  3212.   
  3213.   
  3214. /* copies a news from given newsgroup to the mailbox */
  3215.   
  3216.     static int
  3217.     donndump(argc,argv,p)
  3218.     int argc;
  3219.     char *argv[];
  3220.     void *p;
  3221.     {
  3222.         FILE *t, *f, *o;
  3223.         char *path, *line, *cp, newsname[25], *cp1;
  3224.         struct ffblk blk;
  3225.   
  3226.         if (!Filecheck)
  3227.             if(check_system())
  3228.                 return -1;
  3229.   
  3230.         if ((f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
  3231.             return 0;
  3232.  
  3233.         path = mallocw(LineLen);
  3234.         line = mallocw(LineLen);
  3235.         *path = *line = '\0';
  3236.  
  3237.         for(;;) {
  3238.             if (fgets(line,LineLen,f) == NULL)
  3239.                 break;
  3240.             if (!strncmp(line,argv[1],strlen(argv[1]))) {
  3241.                 cp = strchr(line,' ') + 1;
  3242.                 strcpy(path,cp);
  3243.                 break;
  3244.             }
  3245.             pwait(NULL);
  3246.         }
  3247.         fclose(f);
  3248.   
  3249.         if (*path == '\0') {
  3250.             tprintf("No newsgroup %s\n",argv[1]);
  3251.             goto error;
  3252.         }
  3253.   
  3254.         rip2(path);
  3255.         cp = strrchr(path,'/');
  3256.         cp1 = &newsname[0];
  3257.   
  3258.         while(*cp)
  3259.             *(cp1++) = *(cp++);
  3260.         *cp1 = '\0';
  3261.   
  3262.         strcpy(line,path);
  3263.         strcat(line,"/*.*");
  3264.         if(findfirst(line,&blk,0)) {
  3265.             tputs("No news in newsgroup\n");
  3266.             goto error;
  3267.         }
  3268.         if(argc > 2)
  3269.             sprintf(newsname,"/%s",argv[2]);
  3270.   
  3271.         sprintf(line,"%s%s.txt",Mailspool,newsname);
  3272.         if ((o = open_file(line,"a+",0,1)) == NULLFILE)
  3273.             goto error;
  3274.         if(!(mlock(Mailspool,newsname))) {
  3275.             tprintf("Newsgroup dump to %s\n",line);
  3276.             for (;;) {
  3277.                 if((t = temp_file(0,1)) == NULLFILE) {
  3278.                     fclose(o);
  3279.                     goto error;
  3280.                 }
  3281.                 sprintf(line,"%s/%s",path,blk.ff_name);
  3282.             /* Open the article */
  3283.                 if ((f = open_file(line,READ_TEXT,0,1)) == NULLFILE) {
  3284.                     fclose(t);
  3285.                     fclose(o);
  3286.                     goto error;
  3287.                 }
  3288.                 pwait(NULL);
  3289.                 tputc('.'); /* One dot/article processed */
  3290.                 tflush();
  3291.   
  3292.                 for (;;) {
  3293.                     if (fgets(line,LineLen,f) == NULL)
  3294.                         break;
  3295.                     fputs(line,t);
  3296.                     if (!strnicmp(line,frm,6)) {
  3297.                         cp = strchr(line,' ')+1;
  3298.                         fprintf(o,"From %s",cp);
  3299.                     }
  3300.                 }
  3301.                 rewind(t);
  3302.                 for(;;) {
  3303.                     if (fgets(line,LineLen,t) == NULL)
  3304.                         break;
  3305.                     fputs(line,o);
  3306.                 }
  3307.                 fputc('\n',o);
  3308.                 fclose(t);
  3309.                 fclose(f);
  3310.                 if (findnext(&blk))
  3311.                     break;
  3312.             }
  3313.             rmlock(Mailspool,newsname);
  3314.         } else
  3315.             tputs("Mailfile is busy, try later");
  3316.         fclose(o);
  3317.         tputs("\n");
  3318.   
  3319.         error:
  3320.         free(line);
  3321.         free(path);
  3322.         return 0;
  3323.     }
  3324.   
  3325.   
  3326.     static int
  3327.     donnkick(argc,argv,p)
  3328.     int argc;
  3329.     char *argv[];
  3330.     void *p;
  3331.     {
  3332.         struct Servers *np;
  3333.   
  3334.         for(np = Nntpserver; np != NULLSERVER; np = np->next)
  3335.             if(!stricmp(np->name,argv[1])) {
  3336.             /* If the timer is not running, the timeout function has
  3337.              * already been called and we don't want to call it again.
  3338.              */
  3339.                 if(run_timer(&np->nntpt) || dur_timer(&np->nntpt) == 0) {
  3340.                     stop_timer(&np->nntpt);
  3341.                     poll((void *)np);
  3342.                 }
  3343.                 return 0;
  3344.             }
  3345.         tputs("No server enabled\n");
  3346.         return 0;
  3347.     }
  3348.   
  3349.   
  3350. #ifdef LZW
  3351. /* sets LzwActive flag */
  3352.     static int
  3353.     donnlzw(argc,argv,p)
  3354.     int argc;
  3355.     char *argv[];
  3356.     void *p;
  3357.     {
  3358.         return setbool(&LzwActive,"NNTP LZW",argc,argv);
  3359.     }
  3360. #endif
  3361.   
  3362.   
  3363. /* list nntp servers */
  3364.     static int
  3365.     donnlists(argc,argv,p)
  3366.     int argc;
  3367.     char *argv[];
  3368.     void *p;
  3369.     {
  3370.         struct Servers *np;
  3371.         char tbuf[80];
  3372.   
  3373.         for(np = Nntpserver; np != NULLSERVER; np = np->next) {
  3374.             if (np->lowtime != -1 && np->hightime != -1)
  3375.                 sprintf(tbuf, " -- %02d:%02d-%02d:%02d",
  3376.                 np->lowtime/100, np->lowtime%100,
  3377.                 np->hightime/100, np->hightime%100);
  3378.             else
  3379.                 tbuf[0] = '\0';
  3380.             tprintf("%-32s (%lu/%lu%s)\n   Groups: %s\n", np->name,
  3381.             read_timer(&np->nntpt) /1000L,
  3382.             dur_timer(&np->nntpt) /1000L,
  3383.             tbuf, np->newsgroups ? np->newsgroups : "");
  3384.         }
  3385.         return 0;
  3386.     }
  3387.   
  3388.   
  3389. /* manually entering new news
  3390.  * returncode: -1 if error; 0 success */
  3391.     static int
  3392.     donnpost(argc,argv,p)
  3393.     int argc;
  3394.     char *argv[];
  3395.     void *p;
  3396.     {
  3397.         struct session *sp;
  3398.         struct nntpsv *mp;
  3399.         char buf[LineLen];
  3400.         long id;
  3401.         FILE *f, *idf, *ufp;
  3402.         long currtime;
  3403.   
  3404.         if (!Filecheck)
  3405.             if(check_system())
  3406.                 return -1;
  3407.   
  3408.         if((sp = newsession("Post",0,1)) == NULLSESSION)
  3409.             return -1;
  3410.   
  3411.         mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
  3412.   
  3413.         for (;;) {
  3414.             if ((f = temp_file(0,1)) == NULLFILE)
  3415.                 goto done;
  3416.   
  3417.             id = get_msgid();
  3418.             if (Post->user == NULLCHAR) {
  3419.                 tputs("User name? ");
  3420.                 recvline(sp->input,buf,LineLen);
  3421.                 rip2(buf);
  3422.                 Post->user = strdup(buf);
  3423.             }
  3424.             fprintf(f,"%s%s\n",pth,Post->user);
  3425.             fprintf(f,"%s%s@%s",frm,Post->user,Hostname);
  3426.             if (Post->fullname != NULLCHAR)
  3427.                 fprintf(f," (%s )",Post->fullname);
  3428.             fputc('\n',f);
  3429.   
  3430.             tputs("Newsgroup? ");
  3431.             recvline(sp->input,buf,LineLen);
  3432.             rip2(buf);
  3433.             if (check_blank(buf))
  3434.                 goto done;
  3435.             fprintf(f,"%s%s\n",ngrps,buf);
  3436.   
  3437.             tputs("Subject? ");
  3438.             recvline(sp->input,buf,LineLen);
  3439.             fprintf(f,"%s%s",subj,buf);
  3440.             fprintf(f,"%s<%ld@%s>\n",msgid,id,Hostname);
  3441.             time(&currtime);
  3442.             fprintf(f,"Date: %s",ptime(&currtime));
  3443.             fprintf(f,"Sender: NNTP@%s\n",Hostname);
  3444.   
  3445.             if (Post->reply != NULLCHAR)
  3446.                 fprintf(f,"%s%s\n",replyto,Post->reply);
  3447.   
  3448.             if (Post->organ != NULLCHAR)
  3449.                 fprintf(f,"Organization: %s\n",Post->organ);
  3450.   
  3451.             fputc('\n',f);
  3452.             tputs("Enter message - end with .\n");
  3453.   
  3454.             for (;;) {
  3455.                 recvline(sp->input,buf,LineLen);
  3456.                 if(strcmp(buf,".u\n") == 0
  3457.                 || strcmp(buf,".r\n") == 0) {
  3458.                     tputs("Filename? ");
  3459.                     recvline(sp->input,buf,LineLen);
  3460.                     rip2(buf);
  3461.                     if((ufp = open_file(buf,READ_TEXT,0,1)) != NULLFILE) {
  3462.                         while(fgets(buf,LineLen,ufp) != NULL)
  3463.                             fputs(buf,f);
  3464.                         fclose(ufp);
  3465.                     }
  3466.                     tputs("(continue)\n");
  3467.                 }
  3468.                 if(strcmp(buf,".\n") == 0
  3469.                     || strcmpi(buf,"***END\n") == 0
  3470.                     || strcmpi(buf,"/EX\n") == 0)
  3471.                     break;
  3472.                 fputs(buf,f);
  3473.             }
  3474.   
  3475.             if (Post->sig != NULLCHAR) {
  3476.                 sprintf(buf,"%s",Post->sig);
  3477.                 if ((idf = open_file(buf,READ_TEXT,0,1)) != NULLFILE ) {
  3478.                     while(fgets(buf,LineLen,idf) != NULL)
  3479.                         fputs(buf,f);
  3480.                     fclose(idf);
  3481.                 }
  3482.             }
  3483.   
  3484.             loop:   tputs("\n[Send, Abort, Exit, List] ");
  3485.             recvline(sp->input,buf,LineLen);
  3486.             switch(tolower(buf[0])) {
  3487.                 case 's':
  3488.                     rewind(f);
  3489.                     sprintf(mp->buf,"<%ld@%s>",id,Hostname);
  3490.                     mp->id = strdup(mp->buf);
  3491.                     if (xfer_article2(f,mp) < 1)
  3492.                         tputs("\007Posting failed\n");
  3493.                     break;
  3494.   
  3495.                 case 'l':
  3496.                     rewind(f);
  3497.                     for(;;) {
  3498.                         if (fgets(buf,LineLen,f) == NULL)
  3499.                             break;
  3500.                         tputs(buf);
  3501.                     }
  3502.                     rewind(f);
  3503.                     goto loop;
  3504.   
  3505.                 case 'e':
  3506.                     fclose(f);
  3507.                     goto done;
  3508.   
  3509.                 case 'a':
  3510.                     break;
  3511.   
  3512.                 default:
  3513.                     goto loop;
  3514.             }
  3515.             fclose(f);
  3516.             tputs("Post another? ");
  3517.             recvline(sp->input,buf,LineLen);
  3518.             if (tolower(buf[0]) == 'n')
  3519.                 goto done;
  3520.         }
  3521.   
  3522.         done:
  3523.         if(f != NULLFILE)
  3524.             fclose(f);
  3525.         keywait(NULLCHAR,1);
  3526.         free((char *) mp);
  3527.         freesession(sp);
  3528.         return 0;
  3529.     }
  3530.   
  3531.   
  3532.     static int
  3533.     donnquiet(argc,argv,p)
  3534.     int argc;
  3535.     char *argv[];
  3536.     void *p;
  3537.     {
  3538.         return setintrc(&Nntpquiet,"NNTP quiet",argc,argv,0,2);
  3539.     }
  3540.   
  3541. /* -------------------- Profile subcmds -------------------- */
  3542.   
  3543.     static int
  3544.     donnuser(argc,argv,p)
  3545.     int argc;
  3546.     char *argv[];
  3547.     void *p;
  3548.     {
  3549.         if(argc < 2 && Post->user != NULLCHAR)
  3550.             tprintf("%s\n",Post->user);
  3551.         else {
  3552.             free(Post->user);
  3553.             Post->user = strdup(argv[1]);
  3554.         }
  3555.         return 0;
  3556.     }
  3557.   
  3558.  
  3559.     static int
  3560.     donnsig(argc,argv,p)
  3561.     int argc;
  3562.     char *argv[];
  3563.     void *p;
  3564.     {
  3565.         if(argc < 2 && Post->sig != NULLCHAR)
  3566.             tprintf("%s\n",Post->sig);
  3567.         else {
  3568.             if(access(argv[1],0) == 0) {
  3569.                 free(Post->sig);
  3570.                 Post->sig = strdup(argv[1]);
  3571.             } else {
  3572.                 tputs("No such signature file\n");
  3573.                 return -1;
  3574.             }
  3575.         }
  3576.         return 0;
  3577.     }
  3578.   
  3579.   
  3580.     static int
  3581.     donnfull(argc,argv,p)
  3582.     int argc;
  3583.     char *argv[];
  3584.     void *p;
  3585.     {
  3586.         if(argc < 2 && Post->fullname != NULLCHAR)
  3587.             tprintf("%s\n",Post->fullname);
  3588.         else {
  3589.             free(Post->fullname);
  3590.             Post->fullname = strdup(argv[1]);
  3591.         }
  3592.         return 0;
  3593.     }
  3594.   
  3595.     static int
  3596.     donnhost(argc,argv,p)
  3597.     int argc;
  3598.     char *argv[];
  3599.     void *p;
  3600.     {
  3601.         if(argc < 2 && Host != NULLCHAR)
  3602.             tprintf("%s\n",Host);
  3603.         else {
  3604.             free(Host);
  3605.             Host = strdup(argv[1]);
  3606.         }
  3607.         return 0;
  3608.     }
  3609.   
  3610.     static int
  3611.     donnihave(argc,argv,p)
  3612.     int argc;
  3613.     char *argv[];
  3614.     void *p;
  3615.     {
  3616.         return setintrc(&NnIhave,"NNTP Ihave",argc,argv,0,2);
  3617.     }
  3618.   
  3619.     static int
  3620.     donnorgan(argc,argv,p)
  3621.     int argc;
  3622.     char *argv[];
  3623.     void *p;
  3624.     {
  3625.         if(argc < 2 && Post->organ != NULLCHAR)
  3626.             tprintf("%s\n",Post->organ);
  3627.         else {
  3628.             free(Post->organ);
  3629.             Post->organ = strdup(argv[1]);
  3630.         }
  3631.         return 0;
  3632.     }
  3633.   
  3634.     static int
  3635.     donnread(argc,argv,p)
  3636.     int argc;
  3637.     char *argv[];
  3638.     void *p;
  3639.     {
  3640.         FILE *f;
  3641.         struct session *sp;
  3642.         struct article *art;
  3643.         char cp[LineLen], buf[81];
  3644.         int number, row, Nrows=NROWS, flag = argc;
  3645.   
  3646.         if((art = (struct article *)mallocw(sizeof(struct article))) == NULLARTICLE)
  3647.             return -1;
  3648.   
  3649.         art->group = strdup(argv[1]);
  3650.         if(get_path2(art) == 1) {
  3651.             if(argc > 2) {
  3652.                 number = atoi(argv[2]);
  3653.             } else
  3654.                 number = 1;
  3655.   
  3656.             sprintf(cp,"%s/news.rc",art->path);
  3657.             if(flag < 3 && (f = fopen(cp,READ_TEXT)) != NULLFILE) {
  3658.                 if((fgets(buf,sizeof(buf),f)) != 0) {
  3659.                     number = atoi(buf);
  3660.                     number++;
  3661.                 }
  3662.                 fclose(f);
  3663.             }
  3664.             if((sp = newsession("NNTP read",MORE,0)) != NULLSESSION) {
  3665.                 for(;;) {
  3666.                     if(number < 1)
  3667.                         number = 1;
  3668.                     sp->ttystate.echo = sp->ttystate.edit = 0;
  3669.                     row = Nrows - 4;
  3670.                     sprintf(cp,"%s/%d",art->path,number);
  3671.   
  3672.                     if((f = fopen(cp,READ_TEXT)) != NULLFILE) {
  3673.                         tprintf("Msg #%d\n",number);
  3674.                         while(fgets(buf,sizeof(buf),f),!feof(f)) {
  3675.                             tputs(buf);
  3676.                             if(--row == 0){
  3677.                                 row = keywait("--More--",0);
  3678.                                 switch(row){
  3679.                                     case -1:
  3680.                                     case 'q':
  3681.                                         fclose(f);
  3682.                                         goto done;
  3683.                                     case '\n':
  3684.                                     case '\r':
  3685.                                         row = 2;
  3686.                                         break;
  3687.                                     default:
  3688.                                         row = Nrows - 3;
  3689.                                 }
  3690.                             }
  3691.                         }
  3692.                         fclose(f);
  3693.                     } else {
  3694.                         number--;
  3695.                         tputs("No more news");
  3696.                     }
  3697.                     done:
  3698.                     row = keywait("\nRead next/previous? (n/p/q)",0);
  3699.                     switch(row) {
  3700.                         case -1:
  3701.                         case 'q':
  3702.                             goto done2;
  3703.                         case 'p':
  3704.                             flag = 3;
  3705.                             if(--number < 1)
  3706.                                 goto done2;
  3707.                             continue;
  3708.                         default:
  3709.                             number++;
  3710.                             continue;
  3711.                     }
  3712.                 }
  3713.                 done2:
  3714.                 if(flag < 3) {
  3715.                     sprintf(cp,"%s/news.rc",art->path);
  3716.                     if((f = fopen(cp,WRITE_TEXT)) != NULLFILE) {
  3717.                         sprintf(cp,"%d\n",number);
  3718.                         fputs(cp,f);
  3719.                         fclose(f);
  3720.                     }
  3721.                 }
  3722.                 keywait(NULLCHAR,1);
  3723.                 freesession(sp);
  3724.             }
  3725.         } else {
  3726.             tprintf("No such newsgroup %s\n",art->group);
  3727.         }
  3728.         free(art->path);
  3729.         free(art->group);
  3730.         free(art);
  3731.         return 0;
  3732.     }
  3733.   
  3734.     static int
  3735.     donnreply(argc,argv,p)
  3736.     int argc;
  3737.     char *argv[];
  3738.     void *p;
  3739.     {
  3740.         if(argc < 2 && Post->reply != NULLCHAR)
  3741.             tprintf("%s\n",Post->reply);
  3742.         else {
  3743.             free(Post->reply);
  3744.             Post->reply = strdup(argv[1]);
  3745.         }
  3746.         return 0;
  3747.     }
  3748.   
  3749.   
  3750.   
  3751. /* subcmd parser */
  3752.   
  3753.     static int
  3754.     donnprofile(argc,argv,p)
  3755.     int argc;
  3756.     char *argv[];
  3757.     void *p;
  3758.     {
  3759.         struct cmds Prof[] = {
  3760.             "fullname",     donnfull,       0, 0, NULLCHAR,
  3761.             "host",         donnhost,       0, 0, NULLCHAR,
  3762.             "organ",        donnorgan,      0, 0, NULLCHAR,
  3763.             "reply",        donnreply,      0, 0, NULLCHAR,
  3764.             "sig",          donnsig,        0, 0, NULLCHAR,
  3765.             "user",         donnuser,       0, 0, NULLCHAR,
  3766.             NULLCHAR,
  3767.         };
  3768.   
  3769.         if(Post == NULLPOST) {
  3770.             Post = (struct post *)callocw(1,sizeof(struct post));
  3771.             Post->user = Post->reply = Post->sig = Post->organ = Post->fullname = NULLCHAR;
  3772.         }
  3773.   
  3774.         if (Host == NULLCHAR) {
  3775.             Host = strdup(Hostname);
  3776.         }
  3777.   
  3778.         return (argc == 10) ? 0 : (subcmd(Prof,argc,argv,p));
  3779.     }
  3780.   
  3781.   
  3782.   
  3783. /* cmd parser */
  3784.   
  3785.     int
  3786.     donntp(argc,argv,p)
  3787.     int argc;
  3788.     char *argv[];
  3789.     void *p;
  3790.     {
  3791.   
  3792.         struct cmds Nntp[] = {
  3793.             "active",  donnactive, 0, 0, NULLCHAR,
  3794.             "access",  donnaccess, 0, 0, NULLCHAR,
  3795.             "add",     donnadds,   0, 3, "nntp add <nntpserv> <interval> [<groups>]",
  3796.             "create",  donncreate, 0, 2, "nntp create <newsgroup> [y|n]",
  3797.             "drop",    donndrops,  0, 2, "nntp drop <nntpserv>",
  3798.             "dump",    donndump,   0, 2, "nntp dump <newsgroup> [<mailbox>]",
  3799.             "firstpoll", donnfirstpoll,    0, 0, NULLCHAR,
  3800.             "ihave",   donnihave,  0, 0, NULLCHAR,
  3801.             "kick",    donnkick,   0, 2, "nntp kick <server>",
  3802.             "list",    donnlists,  0, 0, NULLCHAR,
  3803. #ifdef LZW
  3804.             "lzw",     donnlzw,    0, 0, NULLCHAR,
  3805. #endif
  3806.             "post",    donnpost,    2024, 0, NULLCHAR,
  3807.             "profile", donnprofile, 0,    0, NULLCHAR,
  3808.             "read",    donnread,    1024, 2, "nntp read <newsgroup> [number]",
  3809.             "quiet",   donnquiet,   0,    0, NULLCHAR,
  3810.             NULLCHAR,
  3811.         };
  3812.   
  3813.         return (subcmd(Nntp,argc,argv,p));
  3814.     }
  3815.   
  3816.   
  3817.   
  3818. /* main file-opening routine
  3819.  * options: s = socketnumber, if given an error msg is printed to the socket
  3820.  * returncode: NULLFILE if error; filepointer success
  3821.  */
  3822.     FILE *
  3823.     open_file(name,mode,s,t)
  3824.     char *name;
  3825.     char *mode;
  3826.     int s;
  3827.     int t;
  3828.     {
  3829.         FILE *f;
  3830. #ifdef MSDOS
  3831.         register char *cp;
  3832. #endif
  3833.   
  3834.         if(name == NULLCHAR || mode == NULLCHAR)
  3835.             return NULLFILE;
  3836. #ifdef MSDOS
  3837.         while((cp = strchr(name,'\\')) != NULLCHAR)
  3838.             *cp = '/';
  3839. #endif
  3840.         if((f = fopen(name,mode)) == NULLFILE) {
  3841.             if(s)
  3842.                 usprintf(s,fatal,name);
  3843.             if(t)
  3844.                 tprintf("Can't open %s: %s\n",name,sys_errlist[errno]);
  3845.         }
  3846.         return f;
  3847.     }
  3848.   
  3849. /* main tempfile-opening routine
  3850.  * returncode: NULLFILE if error; filepointer success
  3851.  */
  3852.   
  3853.     FILE *
  3854.     temp_file(s,t)
  3855.     int s;
  3856.     int t;
  3857.     {
  3858.         FILE *f;
  3859.   
  3860.         if((f = tmpfile()) == NULLFILE) {
  3861.             if(s)
  3862.                 usprintf(s,fatal,"TMP");
  3863.             if(t) {
  3864.                 tprintf("Can't open TMP: %s\n",sys_errlist[errno]);
  3865.             }
  3866.         }
  3867.         return f;
  3868.     }
  3869.   
  3870. static void
  3871. make_time_string(char *string,time_t *timep)
  3872. {
  3873.     struct tm *stm;
  3874.  
  3875.     stm = localtime(timep);
  3876.     sprintf(string,"%02d%02d%02d %02d%02d%02d",
  3877.       stm->tm_year%100,stm->tm_mon + 1,stm->tm_mday,stm->tm_hour,
  3878.       stm->tm_min,stm->tm_sec);
  3879. }
  3880.  
  3881. #endif /* NNTPS */
  3882.