home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / trn / part06 / rn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-02  |  15.6 KB  |  673 lines

  1. /*  rn -- new readnews program
  2.  *
  3.  *  Original Author: lwall@sdcrdcf.UUCP (Larry Wall)
  4.  *  Organization: System Development Corporation, Santa Monica
  5.  *  Current Author/Maintainer: sob@bcm.tmc.edu (Stan Barber)
  6.  *  Organization: Baylor College of Medicine, Houston,Tx
  7.  *
  8.  *  begun:   01/14/83
  9.  *    1.0: 04/08/83
  10.  *      2.0: 09/01/83
  11.  *      RRN/RN: 11/01/89
  12.  *      4.4  07/04/91
  13.  */
  14. /* This software is Copyright 1991 by Stan Barber. 
  15.  *
  16.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  17.  * use this software as long as: there is no monetary profit gained
  18.  * specifically from the use or reproduction of this software, it is not
  19.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  20.  * included prominently in any copy made. 
  21.  *
  22.  * The author make no claims as to the fitness or correctness of this software
  23.  * for any use whatsoever, and it is provided as is. Any use of this software
  24.  * is at the user's own risk. 
  25.  */
  26.  
  27. static char rnid[] = "@(#)$Id: rn.c,v 4.4.3.1 1991/11/22 04:12:14 davison Trn $";
  28. static char patchlevel[] = "Trn 2.1 based on rn 4.4 pl 2";
  29.  
  30. /* $Log: rn.c,v $
  31.  * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  32.  * Patchlevel 2 changes
  33.  *
  34.  * Revision 4.4.1.1  1991/09/25  19:38:08  sob
  35.  * Updated patchlevel message
  36.  *
  37.  * Revision 4.4  1991/09/09  20:27:37  sob
  38.  * release 4.4
  39.  *
  40.  *
  41.  *
  42.  * 
  43.  */
  44.  
  45. #include "INTERN.h"
  46. #include "common.h"
  47. #include "rn.h"
  48. #ifdef SERVER
  49. #include "server.h"
  50. #endif
  51. #include "EXTERN.h"
  52. #include "rcstuff.h"
  53. #include "term.h"
  54. #include "final.h"
  55. #include "search.h"
  56. #include "ngdata.h"
  57. #include "util.h"
  58. #include "only.h"
  59. #include "ngsrch.h"
  60. #include "help.h"
  61. #include "last.h"
  62. #include "init.h"
  63. #include "intrp.h"
  64. #include "rcln.h"
  65. #include "sw.h"
  66. #include "addng.h"
  67. #include "ng.h"
  68.  
  69. void
  70. rn_init()
  71. {
  72.     ;
  73. }
  74.  
  75. void
  76. main(argc,argv)
  77. int argc;
  78. char *argv[];
  79. {
  80.     bool foundany;
  81.     register char *s;
  82.     bool oh_for_the_good_old_days = FALSE;
  83.     int direction = 1;
  84.  
  85. #if defined(USETHREADS) && !THREAD_INIT
  86.     /* Default to threaded operation if our name starts with a 't' */
  87.     if ((s = rindex(argv[0],'/')) == Nullch)
  88.     s = argv[0];
  89.     else
  90.     s++;
  91.     if (*s == 't')
  92.     use_threads = TRUE;
  93. #endif
  94.     foundany = initialize(argc,argv);
  95.  
  96.     if (maxngtodo)
  97.     starthere = 0;
  98.     else if (!foundany) {        /* nothing to do? */
  99. #ifdef VERBOSE
  100.     if (verbose)
  101.         fputs("\
  102. No unread news in subscribed-to newsgroups.  To subscribe to a new\n\
  103. newsgroup use the g<newsgroup> command.\n\
  104. ",stdout) FLUSH;
  105. #endif
  106.     starthere = nextrcline;
  107.     }
  108.  
  109.     /* loop through all unread news */
  110.  
  111.     {
  112.     bool special = FALSE;        /* temporarily allow newsgroup */
  113.                     /*   with no unread news? */
  114.     bool retry;            /* cycle back to top of list? */
  115.     NG_NUM recent_ng = 0;
  116.     
  117.     current_ng = 0;
  118.     do {
  119.         retry = FALSE;
  120.         if (findlast) {
  121.         findlast = FALSE;
  122.         starthere = 0;
  123.         if (*lastngname) {
  124.             if ((ng = find_ng(lastngname)) == nextrcline)
  125.             ng = 0;
  126.             else {
  127.             set_ngname(lastngname);
  128.                 set_toread(ng);
  129.             if (toread[ng] <= TR_NONE)
  130.                 ng = 0;
  131.             }
  132.         }
  133.         }
  134.         else {
  135.         ng = starthere;
  136.         starthere = 0;
  137.         }
  138.         while (ng <= nextrcline) {    /* for each newsgroup */
  139.         mode = 'n';
  140.         if (ng >= nextrcline) {    /* after the last newsgroup? */
  141.             ng = nextrcline;    /* force it to 1 after */
  142. #ifdef ONLY
  143.             if (maxngtodo) {
  144.             if (retry)
  145. #ifdef VERBOSE
  146.                 IF(verbose)
  147.                 printf("\nRestriction %s%s still in effect.\n",
  148.                     ngtodo[0],
  149.                     maxngtodo > 1 ? ", etc." : nullstr) FLUSH;
  150.                 ELSE
  151. #endif
  152. #ifdef TERSE
  153.                 fputs("\n(\"Only\" mode.)\n",stdout) FLUSH;
  154. #endif
  155.             else {
  156. #ifdef VERBOSE
  157.                 IF(verbose)
  158.                 fputs("\nNo articles under restriction.",
  159.                   stdout) FLUSH;
  160.                 ELSE
  161. #endif
  162. #ifdef TERSE
  163.                 fputs("\nNo \"only\" articles.",stdout) FLUSH;
  164. #endif
  165.                 end_only();    /* release the restriction */
  166.                 retry = TRUE;
  167.             }
  168.             }
  169. #endif
  170.         }
  171.         else {
  172.             bool shoe_fits;    /* newsgroup matches restriction? */
  173.  
  174.             if (toread[ng] >= TR_NONE) {    /* recalc toread? */
  175.             set_ngname(rcline[ng]);
  176.             shoe_fits = inlist(ngname);
  177.             if (shoe_fits)
  178.                 set_toread(ng);
  179.             if (paranoid) {
  180.                 recent_ng = current_ng;
  181.                 current_ng = ng;
  182.                 cleanup_rc();
  183.                     /* this may move newsgroups around */
  184.                 ng = current_ng;
  185.                 set_ngname(rcline[ng]);
  186.             }
  187.             }
  188.             if (toread[ng] < (maxngtodo||special ? TR_NONE : TR_ONE)
  189.              || !shoe_fits) {        /* unwanted newsgroup? */
  190.             ng += direction;    /* then skip it */
  191.             if (ng < 0) {
  192.                ng = 1;
  193.                direction = 1;
  194.             }
  195.             continue;
  196.             }
  197.         }
  198.         special = FALSE;    /* go back to normal mode */
  199.         if (ng != current_ng) {
  200.             recent_ng = current_ng;
  201.                     /* remember previous newsgroup */
  202.             current_ng = ng;    /* remember current newsgroup */
  203.         }
  204.     reask_newsgroup:
  205.         unflush_output();    /* disable any ^O in effect */
  206.         if (ng >= nextrcline) {
  207.             dfltcmd = (retry ? "npq" : "qnp");
  208. #ifdef VERBOSE
  209.             IF(verbose)
  210.             printf("\n******** End of newsgroups--what next? [%s] ",
  211.                 dfltcmd);
  212.             ELSE
  213. #endif
  214. #ifdef TERSE
  215.             printf("\n**** End--next? [%s] ", dfltcmd);
  216. #endif
  217.         } else {
  218. #ifdef USETHREADS
  219.             ThreadedGroup = (use_threads
  220.             && (thread_always || rcchar[ng] == '0'));
  221.             dfltcmd = (use_threads && select_on
  222.             && (ART_NUM)toread[ng] >= select_on ? "+ynq" : "ynq");
  223. #else
  224.             dfltcmd = "ynq";
  225. #endif
  226. #ifdef VERBOSE
  227.             IF(verbose)
  228.             printf("\n******** %3ld unread article%s in %s--read now? [%s] ",
  229.                 (long)toread[ng], (toread[ng]==TR_ONE ? nullstr : "s"),
  230.                 ngname, dfltcmd);
  231.             ELSE
  232. #endif
  233. #ifdef TERSE
  234.             printf("\n**** %3ld in %s--read? [%s] ",
  235.                 (long)toread[ng],
  236.                 ngname,dfltcmd);
  237. #endif
  238.         }
  239.         fflush(stdout);
  240.     reinp_newsgroup:
  241.         eat_typeahead();
  242.         getcmd(buf);
  243.         if (errno || *buf == '\f') {
  244.             putchar('\n') FLUSH; /* if return from stop signal */
  245.             goto reask_newsgroup;    /* give them a prompt again */
  246.         }
  247.         setdef(buf,dfltcmd);
  248. #ifdef VERIFY
  249.         printcmd();
  250. #endif
  251.     do_command:
  252.         direction = 1;        /* default to forward motion */
  253.         switch (*buf) {
  254.         case 'P':        /* goto previous newsgroup */
  255.             special = TRUE;    /* don't skip it if toread==0 */
  256.             /* FALL THROUGH */
  257.         case 'p':        /* find previous unread newsgroup */
  258.             if (ng > 0)
  259.             ng--;
  260.             direction = -1;    /* go backward in the newsrc */
  261.             break;
  262.         case '-':
  263.             ng = recent_ng;    /* recall previous newsgroup */
  264.             if (ng < nextrcline)
  265.             if (!get_ng(rcline[ng],FALSE))
  266.                 ng = current_ng;
  267.             special = TRUE;    /* don't skip it if toread==0 */
  268.             break;
  269.         case 'q': case 'Q': case 'x':    /* quit? */
  270.             oh_for_the_good_old_days = (*buf == 'x');
  271.             putchar('\n') FLUSH;
  272.             ng = nextrcline+1;    /* satisfy */
  273.             retry = FALSE;    /*   loop conditions */
  274.             break;
  275.         case '^':
  276.             putchar('\n') FLUSH;
  277.             ng = 0;
  278.             break;
  279.         case 'n':        /* find next unread newsgroup */
  280.             if (ng == nextrcline) {
  281.             putchar('\n') FLUSH;
  282.             retry = TRUE;
  283.             }
  284.             else if (toread[ng] > TR_NONE)
  285.             retry = TRUE;
  286.             ng++;
  287.             break;
  288.         case 'N':        /* goto next newsgroup */
  289.             special = TRUE;    /* and don't skip it if toread==0 */
  290.             ng++;
  291.             break;
  292.         case '1':        /* goto 1st newsgroup */
  293.             ng = 0;
  294.             special = TRUE;    /* and don't skip it if toread==0 */
  295.             break;
  296.         case '$':
  297.             ng = nextrcline;    /* goto last newsgroup */
  298.             retry = TRUE;
  299.             break;
  300.         case 'L':
  301.             list_newsgroups();
  302.             goto reask_newsgroup;
  303.         case '/': case '?':    /* scan for newsgroup pattern */
  304. #ifdef NGSEARCH
  305.             switch (ng_search(buf,TRUE)) {
  306.             case NGS_ERROR:
  307.             goto reask_newsgroup;
  308.             case NGS_ABORT:
  309.             goto reinp_newsgroup;
  310.             case NGS_INTR:
  311. #ifdef VERBOSE
  312.             IF(verbose)
  313.                 fputs("\n(Interrupted)\n",stdout) FLUSH;
  314.             ELSE
  315. #endif
  316. #ifdef TERSE
  317.                 fputs("\n(Intr)\n",stdout) FLUSH;
  318. #endif
  319.             ng = current_ng;
  320.             goto reask_newsgroup;
  321.             case NGS_FOUND:
  322.             special = TRUE;    /* don't skip it if toread==0 */
  323.             break;
  324.             case NGS_NOTFOUND:
  325. #ifdef VERBOSE
  326.             IF(verbose)
  327.                 fputs("\n\nNot found--use a or g to add newsgroups\n",
  328.                 stdout) FLUSH;
  329.             ELSE
  330. #endif
  331. #ifdef TERSE
  332.                 fputs("\n\nNot found\n",stdout) FLUSH;
  333. #endif
  334.             goto reask_newsgroup;
  335.             }
  336. #else
  337.             notincl("/");
  338. #endif
  339.             break;
  340.         case 'm':
  341. #ifndef RELOCATE
  342.             notincl("m");
  343.             break;
  344. #endif            
  345.         case 'g':    /* goto named newsgroup */
  346.             if (!finish_command(FALSE))
  347.                     /* if they didn't finish command */
  348.             goto reinp_newsgroup;    /* go try something else */
  349.             for (s = buf+1; *s == ' '; s++);
  350.                     /* skip leading spaces */
  351. #ifdef RELOCATE
  352.             if (!*s && *buf == 'm' && ngname && ng < nextrcline)
  353.             strcpy(s,ngname);
  354. #endif
  355.             if (isalpha(*s)) 
  356.             set_ngname(s);
  357.             else {
  358.             if (isdigit(*s)) {
  359.                 int rcnum;
  360.                 rcnum = atoi(s);
  361.                 if (rcnum < nextrcline)
  362.                 set_ngname(rcline[rcnum]);
  363.                 else {
  364.                 printf("\nOnly %d groups. Try again.\n",
  365.                     nextrcline) FLUSH;
  366.                 goto reask_newsgroup;
  367.                 }
  368.             }
  369.             else {
  370.                 printf("\nPlease specify a newsgroup.\n") FLUSH;
  371.                 goto reask_newsgroup;
  372.             }
  373.             }
  374. #ifdef RELOCATE
  375.             if (!get_ng(ngname,*buf=='m'))
  376.                         /* try to find newsgroup */
  377. #else
  378.             if (!get_ng(ngname,FALSE))    /* try to find newsgroup */
  379. #endif
  380.             ng = current_ng;/* if not found, go nowhere */
  381.             special = TRUE;    /* don't skip it if toread==0 */
  382.             break;
  383. #ifdef DEBUGGING
  384.         case 'D':
  385.             printf("\nTries: %d Hits: %d\n",
  386.             softtries,softtries-softmisses) FLUSH;
  387.             goto reask_newsgroup;
  388. #endif
  389.         case '!':        /* shell escape */
  390.             if (escapade())     /* do command */
  391.             goto reinp_newsgroup;
  392.                     /* if rubbed out, re input */
  393.             goto reask_newsgroup;
  394.         case Ctl('k'):        /* edit global KILL file */
  395.             edit_kfile();
  396.             goto reask_newsgroup;
  397.         case 'c':        /* catch up */
  398. #ifdef CATCHUP
  399. reask_catchup:
  400. #ifdef VERBOSE
  401.             IF(verbose)
  402.             in_char("\nDo you really want to mark everything as read? [yn] ", 'C');
  403.             ELSE
  404. #endif
  405. #ifdef TERSE
  406.             in_char("\nReally? [ynh] ", 'C');
  407. #endif
  408.             setdef(buf,"y");
  409. #ifdef VERIFY
  410.             printcmd();
  411. #endif
  412.             putchar('\n') FLUSH;
  413.             if (*buf == 'h') {
  414. #ifdef VERBOSE
  415.             printf("Type y or SP to mark all articles as read.\n");
  416.             printf("Type n to leave articles marked as they are.\n");
  417. #else
  418.             printf("y or SP to mark all read.\n");
  419.             printf("n to forget it.\n");
  420. #endif
  421.             goto reask_catchup;
  422.             }
  423.             else if (*buf != 'y' && *buf != 'n' && *buf != 'q') {
  424.             printf(hforhelp);
  425.             settle_down();
  426.             goto reask_catchup;
  427.             } else if (*buf == 'y' && ng<nextrcline)
  428.             catch_up(ng);
  429.             else
  430.             retry = TRUE;
  431.             ng++;
  432. #else
  433.             notincl("c");
  434. #endif
  435.             break;
  436. #ifdef USETHREADS
  437.         case 't':
  438.             if (!use_threads)
  439.             printf("\n\nNot running in thread mode.\n");
  440.             else if (ng < nextrcline && toread[ng] >= TR_NONE) {
  441.             bool force_threaded = (rcchar[ng] == ':');
  442.             rcchar[ng] = (force_threaded ? '0' : ':');
  443.             printf("\n\n%s will %s.\n", rcline[ng],
  444.                 force_threaded ? "always be read threaded"
  445.                 : "be read unthreaded if no thread file exists"
  446.                 ) FLUSH;
  447.             set_toread(ng);
  448.             }
  449.             special = TRUE;    /* don't skip it if toread==0 */
  450.             break;
  451. #endif
  452.         case 'u':        /* unsubscribe */
  453.             if (ng < nextrcline && toread[ng] >= TR_NONE) {
  454.                     /* unsubscribable? */
  455.             printf(unsubto,rcline[ng]) FLUSH;
  456.             rcchar[ng] = NEGCHAR;
  457.                     /* unsubscribe to (from?) it */
  458.             toread[ng] = TR_UNSUB;
  459.                     /* and make line invisible */
  460.             ng++;        /* do an automatic 'n' */
  461.             }
  462.             break;
  463.         case 'h': {        /* help */
  464.             int cmd;
  465.  
  466.             if ((cmd = help_ng()) > 0)
  467.             pushchar(cmd);
  468.             goto reask_newsgroup;
  469.         }
  470.         case 'A':
  471.             if (ng >= nextrcline)
  472.             break;
  473. reask_abandon:
  474. #ifdef VERBOSE
  475.             IF(verbose)
  476.             in_char("\nAbandon changes to current newsgroup? [yn] ", 'B');
  477.             ELSE
  478. #endif
  479. #ifdef TERSE
  480.             in_char("\nAbandon? [ynh] ", 'B');
  481. #endif
  482.             setdef(buf,"y");
  483. #ifdef VERIFY
  484.             printcmd();
  485. #endif
  486.             putchar('\n') FLUSH;
  487.             if (*buf == 'h') {
  488. #ifdef VERBOSE
  489.             printf("Type y or SP to abandon the changes to this group since you started trn.\n");
  490.             printf("Type n to leave the group as it is.\n");
  491. #else
  492.             printf("y or SP to abandon changes to this group.\n");
  493.             printf("n to forget it.\n");
  494. #endif
  495.             goto reask_abandon;
  496.             }
  497.             else if (*buf != 'y' && *buf != 'n' && *buf != 'q') {
  498.             printf(hforhelp);
  499.             settle_down();
  500.             goto reask_abandon;
  501.             } else if (*buf == 'y')
  502.             abandon_ng(ng);
  503.             special = TRUE;    /* don't skip it if toread==0 */
  504.             break;
  505.         case 'a':
  506. #ifndef FINDNEWNG
  507.             notincl("a");
  508.             goto reask_newsgroup;
  509. #else
  510.             /* FALL THROUGH */
  511. #endif
  512.         case 'o':
  513. #ifdef ONLY
  514.         {
  515. #ifdef FINDNEWNG
  516.             bool doscan = (*buf == 'a');
  517. #endif
  518.  
  519.             if (!finish_command(TRUE)) /* get rest of command */
  520.             goto reinp_newsgroup;    /* if rubbed out, try something else */
  521.             end_only();
  522.             if (buf[1]) {
  523.             bool minusd = instr(buf+1,"-d", TRUE) != Nullch;
  524.  
  525.             sw_list(buf+1);
  526.             if (minusd)
  527.                 cwd_check();
  528.             putchar('\n') FLUSH;
  529. #ifdef FINDNEWNG
  530.             if (doscan && maxngtodo)
  531.                 scanactive();
  532. #endif
  533.             }
  534.             ng = 0;        /* simulate ^ */
  535.             retry = FALSE;
  536.             break;
  537.         }
  538. #else
  539.             notincl("o");
  540.             goto reask_newsgroup;
  541. #endif
  542.         case '&':
  543.             if (switcheroo()) /* get rest of command */
  544.             goto reinp_newsgroup;    /* if rubbed out, try something else */
  545.             goto reask_newsgroup;
  546.         case 'l': {        /* list other newsgroups */
  547.             if (!finish_command(TRUE)) /* get rest of command */
  548.             goto reinp_newsgroup;    /* if rubbed out, try something else */
  549.             for (s = buf+1; *s == ' '; s++);
  550.                         /* skip leading spaces */
  551.             sprintf(cmd_buf,"%s '%s'",filexp(NEWSGROUPS),s);
  552.             resetty();
  553.             if (doshell(sh,cmd_buf))
  554. #ifdef VERBOSE
  555.             IF(verbose)
  556.                 fputs("    (Error from newsgroups program)\n",
  557.                 stdout) FLUSH;
  558.             ELSE
  559. #endif
  560. #ifdef TERSE
  561.                 fputs("(Error)\n",stdout) FLUSH;
  562. #endif
  563.             noecho();
  564.             crmode();
  565.             goto reask_newsgroup;
  566.         }
  567. #ifdef USETHREADS
  568.         case 'U': case '+':
  569. #endif
  570.         case '.': case '=':
  571.         case 'y': case 'Y': case '\t': /* do normal thing */
  572.             if (ng >= nextrcline) {
  573.             fputs("\nNot on a newsgroup.",stdout) FLUSH;
  574.             goto reask_newsgroup;
  575.             }
  576. #ifdef USETHREADS
  577.             else if (*buf == '+' || *buf == 'U' || *buf == '=') {
  578.             buf[1] = '\0';
  579.             s = savestr(buf);
  580.             }
  581. #else
  582.             if (*buf == '=')
  583.             s = savestr("=");
  584. #endif
  585.             else if (*buf == '.') {    /* start command? */
  586.             if (!finish_command(FALSE)) /* get rest of command */
  587.                 goto reinp_newsgroup;
  588.             s = savestr(buf+1);
  589.                     /* do_newsgroup will free it */
  590.             }
  591.             else
  592.             s = Nullch;
  593.             if (toread[ng])
  594.             retry = TRUE;
  595.             switch (do_newsgroup(s)) {
  596.             case NG_ERROR:
  597.             case NG_NORM:
  598.             ng++;
  599.             break;
  600.             case NG_ASK:
  601.             goto reask_newsgroup;
  602.             case NG_SELPRIOR:
  603.             *buf = 'p';
  604.             goto do_command;
  605.             case NG_SELNEXT:
  606.             *buf = 'n';
  607.             goto do_command;
  608.             case NG_MINUS:
  609.             ng = recent_ng;    /* recall previous newsgroup */
  610.             special = TRUE;    /* don't skip it if toread==0 */
  611.             break;
  612.             }
  613.             break;
  614. #ifdef STRICTCR
  615.         case '\n':
  616.             fputs(badcr,stdout) FLUSH;
  617.             goto reask_newsgroup;
  618. #endif
  619.         case 'v':
  620.             printf("\n%s",rnid);
  621.             printf("\n%s",patchlevel);
  622.             printf("\nSend bugs to davison@borland.com\n") FLUSH;
  623.             goto reask_newsgroup;
  624.         default:
  625.             printf("\n%s",hforhelp) FLUSH;
  626.             settle_down();
  627.             goto reask_newsgroup;
  628.         }
  629.         }
  630.     } while (retry);
  631.     }
  632.  
  633.     /* now write .newsrc back out */
  634.  
  635.     write_rc();
  636.  
  637.     if (oh_for_the_good_old_days)
  638.     get_old_rc();
  639.  
  640.     finalize(0);            /* and exit */
  641. }
  642.  
  643. /* set current newsgroup */
  644.  
  645. void
  646. set_ngname(what)
  647. char *what;
  648. {
  649.     int len = strlen(what)+1;
  650.  
  651.     growstr(&ngname,&ngnlen,len);
  652.     strcpy(ngname,what);
  653.     growstr(&ngdir,&ngdlen,len);
  654.     strcpy(ngdir,getngdir(ngname));
  655. }
  656.  
  657. static char *myngdir;
  658. static int ngdirlen = 0;
  659.  
  660. char *
  661. getngdir(ngnam)
  662. char *ngnam;
  663. {
  664.     register char *s;
  665.  
  666.     growstr(&myngdir,&ngdirlen,strlen(ngnam)+1);
  667.     strcpy(myngdir,ngnam);
  668.     for (s = myngdir; *s; s++)
  669.     if (*s == '.')
  670.         *s = '/';
  671.     return myngdir;
  672. }
  673.