home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / trn-3.3 / part06 / trn.c < prev   
C/C++ Source or Header  |  1993-11-27  |  15KB  |  634 lines

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