home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume22 / nn6.4 / part14 / nn.c < prev   
Encoding:
C/C++ Source or Header  |  1990-06-07  |  16.7 KB  |  877 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    The nn user interface main program
  5.  */
  6.  
  7. #include "config.h"
  8. #include "menu.h"
  9. #include "term.h"
  10. #include "keymap.h"
  11. #include "options.h"
  12. #include "proto.h"
  13. #include "articles.h"
  14.  
  15. import char *bin_directory;
  16.  
  17. import int
  18.     seq_cross_filtering,                    /* articles */
  19.     dont_sort_folders,                        /* folder.c */
  20.     dont_split_digests, dont_sort_articles, also_unsub_groups,    /* group.c */
  21.     also_cross_postings,
  22.     case_fold_search,                        /* match.c */
  23.     preview_window, fmt_linenum, fmt_rptsubj,            /* menu.c */
  24.     show_article_date, first_page_lines,            /* more.c */
  25.     keep_rc_backup, no_update,                    /* newsrc.c */
  26.     hex_group_args,                        /* sequence */
  27.     show_current_time, conf_dont_sleep;                /* term.c */
  28.  
  29. export int
  30.     article_limit = -1,
  31.     also_read_articles = 0,
  32.     conf_auto_quit = 0,
  33.     do_kill_handling = 1,
  34.     group_name_args = 0,
  35.     merged_menu = 0,
  36.     repeat_group_query = 0,
  37.     report_cost_on_exit = 1,
  38.     silent = 0,
  39.     verbose = 0,
  40.     Debug = 0;
  41.  
  42. static int
  43.     nngrab_mode = 0,
  44.     prompt_for_group = 0;
  45.  
  46. static char
  47.     *match_subject = NULL,
  48.     *match_sender = NULL,
  49.     *init_file = NULL;
  50.  
  51. Option_Description(nn_options) {
  52.     'a', Int_Option(article_limit),
  53.     'B', Bool_Option(keep_rc_backup),
  54.     'd', Bool_Option(dont_split_digests),
  55.     'f', Bool_Option(dont_sort_folders),
  56.     'g', Bool_Option(prompt_for_group),
  57.     'G', Bool_Option(nngrab_mode),
  58.     'i', Bool_Option(case_fold_search),
  59.     'I', String_Option_Optional(init_file, NULL),
  60.     'k', Bool_Option(do_kill_handling),
  61.     'l', Int_Option(first_page_lines),
  62.     'L', Int_Option_Optional(fmt_linenum, 3),
  63.     'm', Bool_Option(merged_menu),
  64.     'n', String_Option(match_sender),
  65.     'N', Bool_Option(no_update),
  66.     'q', Bool_Option(dont_sort_articles),
  67.     'Q', Bool_Option(silent),
  68.     'r', Bool_Option(repeat_group_query),
  69.     's', String_Option(match_subject),
  70.     'S', Bool_Option(fmt_rptsubj),
  71.     'T', Bool_Option(show_current_time),
  72.     'w', Int_Option_Optional(preview_window, 5),
  73.     'W', Bool_Option(conf_dont_sleep),
  74.     'x', Int_Option_Optional(also_read_articles, -1),
  75.     'X', Bool_Option(also_unsub_groups),
  76.     'Z', Int_Option(Debug),
  77.     '\0',
  78. };
  79.  
  80.  
  81. static int
  82.     report_number_of_articles = 0;
  83. static char
  84.     *check_message_format = NULL;
  85. import int
  86.     quick_unread_count;
  87.  
  88. Option_Description(check_options) {
  89.     'Q', Bool_Option(silent),
  90.     'r', Bool_Option(report_number_of_articles),
  91.     'f', String_Option(check_message_format),
  92.     't', Bool_Option(verbose),
  93.     'v', Bool_Option(verbose),
  94.     'c', Bool_Option(quick_unread_count),
  95.     '\0',
  96. };
  97.  
  98. /* program name == argv[0] without path */
  99.  
  100. char *pname;
  101.  
  102. static int must_unlock = 0;
  103.  
  104. static int nn_locked()
  105. {
  106.     if (no_update) return 0;
  107.  
  108.     switch (who_am_i) {
  109.      case I_AM_ADMIN:
  110.      case I_AM_CHECK:
  111.      case I_AM_POST:
  112.      case I_AM_GREP:
  113.      case I_AM_SPEW:
  114.     return 0;        /* will not update .newsrc */
  115.     }
  116.  
  117.     if (proto_lock(I_AM_NN, PL_SET)) {
  118.     printf("\nAnother nn process is already running\n\n");
  119.     return 1;
  120.     }
  121.  
  122.     must_unlock = 1;
  123.     return 0;
  124. }
  125.  
  126. static flag_type setup_access()
  127. {
  128.     flag_type access_mode = 0;
  129.  
  130.     if (do_kill_handling)
  131.     access_mode |= ACC_DO_KILL;
  132.     if (also_cross_postings)
  133.     access_mode |= ACC_ALSO_CROSS_POSTINGS;
  134.     if (also_read_articles)
  135.     access_mode |= ACC_ALSO_READ_ARTICLES;
  136.     if (dont_split_digests)
  137.     access_mode |= ACC_DONT_SPLIT_DIGESTS;
  138.     if (dont_sort_articles)
  139.     access_mode |= ACC_DONT_SORT_ARTICLES;
  140.  
  141.     return access_mode;
  142. }
  143.  
  144. export group_header *jump_to_group = NULL;
  145.  
  146. static read_news(access_mode, mask)
  147. flag_type access_mode;
  148. char *mask;
  149. {
  150.     register group_header *gh, *prev, *tmp, *after_loop;
  151.     flag_type group_mode;
  152.     int menu_cmd;
  153.     int must_clear = 0, did_jump = 0;
  154.     extern int menu();
  155.  
  156.     prev = group_sequence;
  157.     gh = group_sequence;
  158.     after_loop = NULL;
  159.  
  160.     for (;;) {
  161.     group_mode = access_mode;
  162.     
  163.     if (s_hangup) break;
  164.  
  165.     if (gh == NULL) {
  166.         if (after_loop != NULL) {
  167.         gh = after_loop;
  168.         after_loop = NULL;
  169.         if (gh->unread_count <= 0)
  170.             group_mode |= ACC_ORIG_NEWSRC;
  171.         goto enter_direct;
  172.         }
  173.  
  174.         if (did_jump) {
  175.         did_jump = 0;
  176.         gh = group_sequence;
  177.         continue;
  178.         }
  179.  
  180.         if (must_clear && conf_auto_quit) {
  181.         prompt("\1LAST GROUP READ.  QUIT NOW?\1");
  182.         switch (yes(1)) {
  183.          case 1:
  184.             break;
  185.          case 0:
  186.             gh = group_sequence;
  187.          default:
  188.             after_loop = prev;
  189.             continue;
  190.         }
  191.         }
  192.         break;
  193.     }
  194.  
  195.     if (gh->group_flag & G_UNSUBSCRIBED) {
  196.         if (!also_unsub_groups) {
  197.         gh = gh->next_group;
  198.         continue;
  199.         }
  200.     } else
  201.         if (!also_read_articles && gh->unread_count <= 0) {
  202.         gh = gh->next_group;
  203.         continue;
  204.         }
  205.  
  206.      enter_direct:
  207.  
  208.     free_memory();
  209.  
  210.     if (gh->group_flag & G_FOLDER) {
  211.         menu_cmd = folder_menu(gh->group_name);
  212.         if (menu_cmd == ME_NO_REDRAW) {
  213.         menu_cmd = ME_NO_ARTICLES;
  214.         gh->last_db_article = 0;
  215.         }
  216.     } else {
  217.         group_mode |= setup_access();
  218.         if (group_mode & ACC_ORIG_NEWSRC)
  219.         gh->last_article = gh->first_article;
  220.         
  221.         menu_cmd = group_menu(gh, (article_number)(-1), group_mode, mask, menu);
  222.         group_mode = access_mode;
  223.     }
  224.  
  225.     if (menu_cmd != ME_NO_ARTICLES) {
  226.         after_loop = NULL;
  227.         must_clear++;
  228.     }
  229.  
  230.     switch (menu_cmd) {
  231.  
  232.      case ME_QUIT:    /* or jump */
  233.         if (!jump_to_group) return must_clear;
  234.  
  235.         prev = jump_to_group;
  236.         jump_to_group = NULL;
  237.         did_jump = 1;
  238.         /* fall thru */
  239.  
  240.      case ME_PREV:
  241.         tmp = gh;
  242.         gh = prev;
  243.         prev = tmp;
  244.         if (gh->unread_count <= 0)
  245.         group_mode |= ACC_ORIG_NEWSRC;
  246.         goto enter_direct;
  247.  
  248.      case ME_NEXT:
  249.         prev = gh;
  250.         /* fall thru */
  251.  
  252.      case ME_NO_ARTICLES:
  253.         if (gh->group_flag & G_MERGE_HEAD) {
  254.         do gh = gh->next_group;
  255.             while (gh && (gh->group_flag & G_MERGE_SUB));
  256.         } else
  257.         gh = gh->next_group;
  258.         continue;
  259.     }
  260.     }
  261.     return must_clear;
  262. }
  263.  
  264.  
  265. static catch_up()
  266. {
  267.     register group_header *gh;
  268.     char answer[50];
  269.     int mode, must_help;
  270.     import int newsrc_update_freq, novice;
  271.     import int menu();
  272.     flag_type access_mode;
  273.  
  274.     access_mode = setup_access();
  275.     
  276.     prt_unread("\nCatch-up on %u ? (auto)matically (i)nteractive ");
  277.     fl;
  278.     mode = 0;
  279.  
  280.     if (gets(answer)) {
  281.     if (strncmp(answer, "auto", 4) == 0) {
  282.         printf("\nUPDATING .newsrc FILE....");
  283.         fl;
  284.         mode = -1;
  285.     } else
  286.     if (*answer == 'i')
  287.         mode = 1;
  288.     }
  289.  
  290.     if (mode == 0) {
  291.     printf("\nNO UPDATE\n");
  292.     return;
  293.     }
  294.  
  295.     newsrc_update_freq = 9999;
  296.     must_help = novice;
  297.  
  298.     Loop_Groups_Sequence(gh) {
  299.  
  300.     if ((gh->group_flag & G_COUNTED) == 0) continue;
  301.  
  302.     if (mode < 0) {
  303.         update_rc_all(gh, 0);
  304.         continue;
  305.     }
  306.  
  307.      again:
  308.     if (must_help) {
  309.         printf("\n  y - mark all articles as read in current group\n");
  310.         printf("  n - do not update group\n");
  311.         printf("  r - read the group now\n");
  312.         printf("  U - unsubscribe to current group\n");
  313.         printf("  ? - this message\n");
  314.         printf("  q - quit\n\n");
  315.  
  316.         must_help = 0;
  317.     }
  318.  
  319.     printf("Update %s (%ld)? (ynrU?q) n\b", gh->group_name,
  320.            (long)(gh->last_db_article - gh->last_article));
  321.     fl;
  322.  
  323.     if (gets(answer) == NULL || s_keyboard)
  324.         *answer = 'q';
  325.  
  326.     switch (*answer) {
  327.  
  328.      case 'q':
  329.         putchar(NL);
  330.         printf("Update rest? (yn) n\b");
  331.         fl;
  332.         if (gets(answer) == NULL || *answer != 'y')
  333.         return;
  334.  
  335.         mode = -1;
  336.         break;
  337.  
  338.      case NUL:
  339.      case 'n':
  340.         continue;
  341.  
  342.      case 'r':
  343.         raw();
  344.         group_menu(gh, (article_number)(-1), access_mode, (char *)NULL, menu);
  345.         unset_raw();
  346.         clrdisp();
  347.         if (gh->unread_count > 0) goto again;
  348.         continue;
  349.  
  350.      case 'U':
  351.         update_rc_all(gh, 1);
  352.         continue;
  353.  
  354.      case 'y':
  355.         break;
  356.  
  357.      default:
  358.         must_help = 1;
  359.         goto again;
  360.     }
  361.  
  362.     update_rc_all(gh, 0);
  363.     }
  364.  
  365.     printf("DONE\n");
  366.  
  367.     flush_newsrc();
  368. }
  369.  
  370. export char *mail_box = NULL;
  371.  
  372. unread_mail(t)
  373. time_t t;
  374. {
  375.     struct stat st;
  376.     static time_t next = 0;
  377.     static int any = 0;
  378.  
  379.     if (next > t) return any;
  380.  
  381.     next = t + 60;
  382.     any = 0;
  383.  
  384.     if (mail_box == NULL ||
  385.     stat(mail_box, &st) != 0 ||
  386.     st.st_size == 0 ||
  387.     st.st_mtime < st.st_atime) return 0;
  388.  
  389.     any = 1;
  390.  
  391.     return 1;
  392. }
  393.  
  394. #ifdef ACCOUNTING
  395. #ifndef STATISTICS
  396. #define STATISTICS 1
  397. #endif
  398. #define NEED_ACCOUNT
  399. #else
  400. #ifdef AUTHORIZE
  401. #define NEED_ACCOUNT
  402. #endif
  403. #endif
  404.  
  405. #ifdef STATISTICS
  406. static time_t usage_time = 0;
  407. static time_t last_tick = 0;
  408.  
  409. stop_usage()
  410. {
  411.     last_tick = 0;
  412. }
  413.  
  414. time_t tick_usage()
  415. {
  416.     register time_t now;
  417.  
  418.     now = cur_time();
  419.  
  420.     /*
  421.      * We ignore ticks > 2 minutes because the user has probably
  422.      * just left the terminal inside nn and done something else
  423.      */
  424.     if (last_tick > (now - 120))
  425.     usage_time += now - last_tick;
  426.  
  427.     last_tick = now;
  428.     return now;
  429. }
  430.  
  431. log_usage()
  432. {
  433. #ifdef ACCOUNTING
  434.     account('U', report_cost_on_exit);
  435. #else
  436.     if (usage_time < (STATISTICS * 60)) return; /* don't log short sessions */
  437.  
  438.     usage_time /= 60;
  439.     log_entry('U', "USAGE %d.%02d", usage_time/60, usage_time%60);
  440. #endif
  441. }
  442.  
  443. #else
  444. stop_usage()
  445. {
  446. }
  447.  
  448. time_t tick_usage()
  449. {
  450.     return cur_time();
  451. }
  452.  
  453. log_usage()
  454. {
  455. }
  456. #endif
  457.  
  458. #ifdef NEED_ACCOUNT
  459. account(option, report)
  460. char option;
  461. int report;
  462. {
  463.     char *args[10], **ap;
  464.     char buf1[16], buf2[16];
  465.     int ok;
  466.  
  467.     if (who_am_i != I_AM_NN && who_am_i != I_AM_POST) return 0;
  468.  
  469.     if (report) {
  470.     putchar(CR); clrline(); fl;
  471.     }
  472.  
  473.     ap = args;
  474.     *ap++ = "nnacct";
  475.     if (report) *ap++ = "-r";
  476.     sprintf(buf1, "-%c%ld", option, (long)usage_time/60);
  477.     *ap++ = buf1;
  478.     sprintf(buf2, "-W%d", who_am_i);
  479.     *ap++ = buf2;
  480.     *ap++ = NULL;
  481.     ok = execute(relative(bin_directory, "nnacct"), args, 0);
  482.     if (option == 'U' && report) putchar(NL);
  483.     return ok;
  484. }
  485. #endif
  486.  
  487. /* this will go into emacs_mode.c when it is completed someday */
  488.  
  489. emacs_mode()
  490. {
  491.     printf("EMACS MODE IS NOT SUPPORTED YET.\n");
  492. }
  493.  
  494.  
  495. static do_nnspew()
  496. {
  497.     register group_header *gh;
  498.     import int seq_cross_filtering;
  499.     int ix;
  500.  
  501.     ix = 0;
  502.     Loop_Groups_Header(gh) {
  503.     if (gh->master_flag & M_IGNORE_GROUP) continue;
  504.     gh->preseq_index = ++ix;
  505.     }
  506.  
  507.     /* Only output each article once */
  508.     /* Must also use this mode when using nngrab! */
  509.  
  510.     seq_cross_filtering = 1;
  511.  
  512.     Loop_Groups_Header(gh) {
  513.     if (s_hangup) return 1;
  514.     if (gh->master_flag & M_IGNORE_GROUP) continue;
  515.     access_group(gh, gh->first_db_article, gh->last_db_article,
  516.              ACC_DONT_SORT_ARTICLES | ACC_ALSO_FULL_DIGEST |
  517.              ACC_SPEW_MODE, (char *)NULL);
  518.     }
  519.     return 0;
  520. }
  521.  
  522.  
  523. clean_group(gh)
  524. group_header *gh;
  525. {
  526. }
  527.  
  528. main(argc, argv)
  529. int argc;
  530. char *argv[];
  531. {
  532.     extern long unread_articles;
  533.     extern char *program_name();
  534.     int say_welcome = 0, cmd;
  535.     flag_type access_mode;
  536.     char *mask;
  537.  
  538.     pname = program_name(argv);
  539.  
  540.     if (strcmp(pname, "nnadmin") == 0) {
  541.     who_am_i = I_AM_ADMIN;
  542.     } else
  543.     if (strcmp(pname, "nnemacs") == 0) {
  544.     who_am_i = I_AM_EMACS;
  545.     } else
  546.     if (strcmp(pname, "nncheck") == 0) {
  547.     who_am_i = I_AM_CHECK;
  548.     } else
  549.     if (strcmp(pname, "nntidy") == 0) {
  550.     who_am_i = I_AM_TIDY;
  551.     } else
  552.     if (strcmp(pname, "nngoback") == 0) {
  553.     who_am_i = I_AM_GOBACK;
  554.     } else
  555.     if (strcmp(pname, "nngrep") == 0) {
  556.     who_am_i = I_AM_GREP;
  557.     } else
  558.     if (strcmp(pname, "nnpost") == 0) {
  559.     who_am_i = I_AM_POST;
  560.     } else {
  561.     who_am_i = I_AM_NN;
  562.     }
  563.  
  564.     if (who_am_i == I_AM_NN || (who_am_i == I_AM_ADMIN && argc == 1)) {
  565.     if (!isatty(0)) {
  566.         if (who_am_i == I_AM_NN && argc == 2) {
  567.         if (strcmp(argv[1], "-SPEW") == 0) {
  568.             who_am_i = I_AM_SPEW;
  569.             init_global();
  570.             goto nnspew;
  571.         }
  572.         }
  573.  
  574.         fprintf(stderr, "Input is not a tty\n");
  575.         exit(1);
  576.     }
  577.     }
  578.  
  579. #ifdef AUTHORIZE
  580.     init_execute();
  581.     if (cmd = account('P', 0)) {
  582.     switch (cmd) {
  583.      case 1:
  584.         if (who_am_i == I_AM_POST) {
  585.         printf("You are not authorized to post news\n");
  586.         exit(41);
  587.         }
  588.         /* ok_to_post = 0; */
  589.         cmd = 0;
  590.         break;
  591.      case 2:
  592.         printf("You are not authorized to read news\n");
  593.         break;
  594.      case 3:
  595.         printf("You cannot read news at this time\n");
  596.         break;
  597.      case 4:
  598.         printf("Your news reading quota is exceeded\n");
  599.         break;
  600.      default:
  601.         printf("Bad authorization -- reason %d\n", cmd);
  602.         break;
  603.     }
  604.     if (cmd) exit(40 + cmd);
  605.     }
  606. #endif
  607.  
  608.     if ((say_welcome = init_global()) < 0) {
  609.     printf("%s: nn must been invoked to initialize user files\n", pname);
  610.     nn_exit(1);
  611.     }
  612.  
  613. #ifdef NNTP
  614.     nntp_check();
  615. #endif
  616.  
  617.     init_key_map();
  618. #ifndef AUTHORIZE
  619.     init_execute();
  620. #endif
  621.     init_macro();
  622.  
  623.  nnspew:
  624.  
  625.     open_master(OPEN_READ);
  626.  
  627.     switch (who_am_i) {
  628.  
  629.      case I_AM_NN:
  630.     init_term();
  631.  
  632.     if (say_welcome) {
  633.         display_file("adm.welcome", CLEAR_DISPLAY | CONFIRMATION);
  634.         clrdisp();
  635.     }
  636.  
  637.     visit_init_file(0, argv[1]);
  638.  
  639.     group_name_args =
  640.         parse_options(argc, argv, (char *)NULL, nn_options,
  641.               " [group | [+]folder]...");
  642.  
  643.     if (also_read_articles) {
  644.         if (article_limit < 0)
  645.         article_limit = also_read_articles;
  646.         do_kill_handling = 0;
  647.         no_update++;
  648.     }
  649.  
  650.     if (match_subject) {
  651.         mask = match_subject;
  652.         access_mode = ACC_ON_SUBJECT;
  653.     } else if (match_sender) {
  654.         mask = match_sender;
  655.         access_mode = ACC_ON_SENDER;
  656.     } else {
  657.         mask = NULL;
  658.         access_mode = 0;
  659.     }
  660.  
  661.     if (mask) {
  662.         if (case_fold_search) fold_string(mask);
  663.         no_update++;
  664.         do_kill_handling = 0;
  665.     }
  666.  
  667.     if (nngrab_mode) {
  668.         seq_cross_filtering = 1;
  669.         hex_group_args = 1;
  670.         no_update = 1;
  671.     }
  672.  
  673.     if (merged_menu) {
  674.         no_update++;
  675.     }
  676.  
  677.     if (!no_update && group_name_args > 0)
  678.         no_update = only_folder_args(argv + 1);
  679.  
  680.     break;
  681.  
  682.      case I_AM_ADMIN:
  683.     if (argc == 1) {
  684.         init_term();
  685.         visit_init_file(0, (char *)NULL);
  686.     }
  687.     admin_mode(argv[1]);
  688.     nn_exit(0);
  689.  
  690.      case I_AM_CHECK:
  691.     visit_init_file(1, (char *)NULL);
  692.     group_name_args =
  693.         parse_options(argc, argv, (char *)NULL, check_options,
  694.               " [group]...");
  695.     break;
  696.  
  697.      case I_AM_EMACS:
  698.     silent = 1;
  699.     break;
  700.  
  701.      case I_AM_TIDY:
  702.     visit_init_file(1, (char *)NULL);
  703.     group_name_args = opt_nntidy(argc, argv);
  704.     break;
  705.  
  706.      case I_AM_GOBACK:
  707.     group_name_args = opt_nngoback(argc, &argv);
  708.     break;
  709.  
  710.      case I_AM_GREP:
  711.     visit_init_file(1, (char *)NULL);
  712.     opt_nngrep(argc, argv);
  713.     silent = 1;
  714.     break;
  715.  
  716.      case I_AM_POST:
  717.     do_nnpost(argc, argv);
  718.     nn_exit(0);
  719.  
  720.      case I_AM_SPEW:
  721.     if (proto_lock(I_AM_SPEW, PL_SET) == 0) {
  722.         cmd = do_nnspew();
  723.         proto_lock(I_AM_SPEW, PL_CLEAR);
  724.     } else
  725.         cmd = 1;    /* don't interfere with other nnspew */
  726.     nn_exit(cmd);
  727.     }
  728.  
  729.     if (!silent || who_am_i == I_AM_CHECK)
  730.     printf("Release %s,  Kim F. Storm, 1990\n\n", version_id);
  731.  
  732.     if (nn_locked()) nn_exit(2);
  733.  
  734.     visit_rc_file();
  735.  
  736.     if (group_name_args > 0)
  737.     named_group_sequence(argv + 1);
  738.     else
  739.     normal_group_sequence();
  740.  
  741.     if (who_am_i != I_AM_TIDY && who_am_i != I_AM_GOBACK)
  742.     count_unread_articles();
  743.  
  744.     switch (who_am_i) {
  745.  
  746.      case I_AM_EMACS:
  747.     prt_unread("%U %G\n");
  748.     emacs_mode();
  749.     break;
  750.  
  751.      case I_AM_CHECK:
  752.     if (report_number_of_articles) {
  753.         prt_unread("%U");
  754.         break;
  755.     }
  756.  
  757.     if (check_message_format) {
  758.         if (unread_articles || !silent)
  759.         prt_unread(check_message_format);
  760.     } else
  761.     if (!silent) {
  762.         if (unread_articles || report_number_of_articles)
  763.         prt_unread("There %i %u in %g\n");
  764.         else
  765.         prt_unread((char *)NULL);
  766.     }
  767.  
  768.     nn_exit( unread_articles ? 0 : 99 );
  769.     /*NOTREACHED*/
  770.  
  771.      case I_AM_TIDY:
  772.     do_tidy_newsrc();
  773.     break;
  774.  
  775.      case I_AM_GOBACK:
  776.     do_goback();
  777.     break;
  778.  
  779.      case I_AM_NN:
  780.     if (unread_articles == 0 &&
  781.         group_name_args == 0 &&
  782.         !also_read_articles &&
  783.         !prompt_for_group) {
  784.         if (!silent) prt_unread((char *)NULL);
  785.         break;
  786.     }
  787.  
  788.     if (do_kill_handling)
  789.         do_kill_handling = init_kill();
  790.  
  791.     if (prompt_for_group) {
  792.         import int also_cross_postings;
  793.  
  794.         if (mask != NULL)
  795.         user_error("Cannot use -s/-n with -g\n\r");
  796.         
  797.         also_cross_postings = 1;
  798.         do {
  799.         raw();
  800.         clrdisp();
  801.         current_group = NULL;
  802.         prompt_line = 2;
  803.         cmd = goto_group(K_GOTO_GROUP, (article_header *)NULL, setup_access());
  804.         
  805.         } while (repeat_group_query && cmd != ME_QUIT && cmd != ME_NO_REDRAW);
  806.         clrdisp();
  807.         unset_raw();
  808.         break;
  809.     }
  810.  
  811.     if (!no_update && article_limit == 0) {
  812.         catch_up();
  813.         break;
  814.     }
  815.  
  816.     if (merged_menu) {
  817.         merge_and_read(access_mode | setup_access(), mask);
  818.         clrdisp();
  819.         break;
  820.     }
  821.  
  822.     if (read_news(access_mode, mask)) {
  823.         clrdisp();
  824.  
  825.         if (master.db_lock[0])
  826.         printf("Database has been locked:\n%s\n", master.db_lock);
  827.  
  828.         if (!also_read_articles &&
  829.         unread_articles > 0 &&
  830.         !silent && group_name_args == 0)
  831.         prt_unread("There %i still %u in %g\n\n\r");
  832.         break;
  833.     }
  834.     gotoxy(0,Lines-1);
  835.     if (group_name_args == 0)
  836.         printf("No News\n");
  837.     else
  838.         printf("\r\n");
  839.     break;
  840.  
  841.      case I_AM_GREP:
  842.     do_grep(argv+1);
  843.     break;
  844.     }
  845.  
  846.     nn_exit(0);
  847.     /*NOTREACHED*/
  848. }
  849.  
  850. /*
  851.  * nn_exit() --- called whenever a program exits.
  852.  */
  853.  
  854. nn_exit(n)
  855. {
  856.     static int loop = 0;
  857.  
  858.     if (loop) exit(n);
  859.     loop++;
  860.  
  861.     visual_off();
  862.  
  863. #ifdef NNTP
  864.     nntp_cleanup();
  865. #endif /* NNTP */
  866.     close_master();
  867.     flush_newsrc();
  868.  
  869.     if (who_am_i == I_AM_NN)
  870.     log_usage();
  871.  
  872.     if (must_unlock)
  873.     proto_lock(I_AM_NN, PL_CLEAR);
  874.  
  875.     exit(n);
  876. }
  877.