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