home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume23 / trn / part09 / rn.c < prev   
C/C++ Source or Header  |  1991-08-22  |  15KB  |  622 lines

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