home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / nn.c < prev    next >
C/C++ Source or Header  |  1996-08-19  |  23KB  |  1,141 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 "keymap.h"
  10. #include "nn_term.h"
  11. #include "options.h"
  12. #include "proto.h"
  13. #include "articles.h"
  14. #ifdef USE_MALLOC_H
  15. #include <malloc.h>
  16. #endif
  17.  
  18. /* nn.c */
  19.  
  20. static int nn_locked __APROTO((void));
  21. static group_header *last_group_maint __APROTO((group_header *last, int upd));
  22. static read_news __APROTO((flag_type access_mode, char *mask));
  23. static void catch_up __APROTO((void));
  24. static do_nnspew __APROTO((void));
  25. static void prt_version __APROTO((void));
  26. static void do_db_check __APROTO((void));
  27.  
  28.  
  29.  
  30. import char *bin_directory;
  31.  
  32. import int
  33.     seq_cross_filtering,                    /* articles */
  34.     dont_sort_folders,                        /* folder.c */
  35.     dont_split_digests, dont_sort_articles, also_unsub_groups,    /* group.c */
  36.     also_cross_postings,
  37.     case_fold_search,                        /* match.c */
  38.     preview_window, fmt_linenum, fmt_rptsubj,            /* menu.c */
  39.     show_article_date, first_page_lines,            /* more.c */
  40.     keep_rc_backup, no_update,                    /* newsrc.c */
  41.     hex_group_args,                        /* sequence */
  42.     show_current_time, conf_dont_sleep;                /* term.c */
  43.  
  44. export int
  45.     article_limit = -1,
  46.     also_read_articles = 0,
  47.     also_full_digest = 0,
  48.     batch_mode = 0,
  49.     conf_auto_quit = 0,
  50.     do_kill_handling = 1,
  51.     group_name_args = 0,
  52.     merged_menu = 0,
  53.     prev_also_read = 1,
  54.     repeat_group_query = 0,
  55.     report_cost_on_exit = 1,
  56.     show_motd_on_entry = 1,
  57.     silent = 0,
  58.     verbose = 0,
  59.     Debug = 0;
  60.  
  61. export int check_db_update = 12 /* HOURS */;
  62.  
  63. extern char proto_host[];
  64. import int newsrc_update_freq, novice;
  65. import int seq_cross_filtering;
  66. import char *news_active;
  67. extern long unread_articles;
  68. extern long initial_memory_break;
  69. extern int first_time_user;
  70. import int also_cross_postings;
  71.  
  72.  
  73. #ifndef HAVE_UNISTD_H
  74. extern char *sbrk();
  75. #endif
  76. #ifdef NOV
  77. extern void novartdir();
  78. #endif
  79.  
  80. static int
  81.     nngrab_mode = 0,
  82.     prompt_for_group = 0;
  83.  
  84. static char
  85.     *match_subject = NULL,
  86.     *match_sender = NULL,
  87.     *init_file = NULL;
  88.  
  89. Option_Description(nn_options) {
  90.     'a', Int_Option(article_limit),
  91.     'B', Bool_Option(keep_rc_backup),
  92.     'd', Bool_Option(dont_split_digests),
  93.     'f', Bool_Option(dont_sort_folders),
  94.     'g', Bool_Option(prompt_for_group),
  95.     'G', Bool_Option(nngrab_mode),
  96.     'i', Bool_Option(case_fold_search),
  97.     'I', String_Option_Optional(init_file, NULL),
  98.     'k', Bool_Option(do_kill_handling),
  99.     'l', Int_Option(first_page_lines),
  100.     'L', Int_Option_Optional(fmt_linenum, 3),
  101.     'm', Bool_Option(merged_menu),
  102.     'n', String_Option(match_sender),
  103.     'N', Bool_Option(no_update),
  104.     'q', Bool_Option(dont_sort_articles),
  105.     'Q', Bool_Option(silent),
  106.     'r', Bool_Option(repeat_group_query),
  107.     's', String_Option(match_subject),
  108.     'S', Bool_Option(fmt_rptsubj),
  109.     'T', Bool_Option(show_current_time),
  110.     'w', Int_Option_Optional(preview_window, 5),
  111.     'W', Bool_Option(conf_dont_sleep),
  112.     'x', Int_Option_Optional(also_read_articles, -1),
  113.     'X', Bool_Option(also_unsub_groups),
  114.     'Z', Int_Option(Debug),
  115.     '\0',
  116. };
  117.  
  118.  
  119. static int
  120.     report_number_of_articles = 0;
  121. static char
  122.     *check_message_format = NULL;
  123. import int
  124.     quick_unread_count;
  125.  
  126. Option_Description(check_options) {
  127.     'Q', Bool_Option(silent),
  128.     'r', Bool_Option(report_number_of_articles),
  129.     'f', String_Option(check_message_format),
  130.     't', Bool_Option(verbose),
  131.     'v', Bool_Option(verbose),
  132.     'c', Bool_Option(quick_unread_count),
  133.     '\0',
  134. };
  135.  
  136. /* program name == argv[0] without path */
  137.  
  138. char *pname;
  139.  
  140. static int must_unlock = 0;
  141.  
  142. static int nn_locked()
  143. {
  144.     if (no_update) return 0;
  145.  
  146.     switch (who_am_i) {
  147.      case I_AM_ADMIN:
  148.      case I_AM_CHECK:
  149.      case I_AM_POST:
  150.      case I_AM_GREP:
  151.      case I_AM_SPEW:
  152.      case I_AM_VIEW:
  153.     return 0;        /* will not update .newsrc */
  154.     }
  155.  
  156.     if (proto_lock(I_AM_NN, PL_SET)) {
  157.     
  158.     if (proto_host[0])
  159.         nn_exitmsg(1, "\nnn is running on host %s\nor .nn/LOCK should be removed.\n\n", proto_host);
  160.     else
  161.         nn_exitmsg(1, "\nAnother nn process is already running\n\n");
  162.     }
  163.  
  164.     must_unlock = 1;
  165.     return 0;
  166. }
  167.  
  168. #define setup_access()    ACC_PARSE_VARIABLES
  169.  
  170. flag_type parse_access_flags()
  171. {
  172.     flag_type access_mode = 0;
  173.  
  174.     if (do_kill_handling)
  175.     access_mode |= ACC_DO_KILL;
  176.     if (also_cross_postings)
  177.     access_mode |= ACC_ALSO_CROSS_POSTINGS;
  178.     if (also_read_articles)
  179.     access_mode |= ACC_ALSO_READ_ARTICLES;
  180.     if (dont_split_digests)
  181.     access_mode |= ACC_DONT_SPLIT_DIGESTS;
  182.     if (also_full_digest)
  183.     access_mode |= ACC_ALSO_FULL_DIGEST;
  184.     if (dont_sort_articles)
  185.     access_mode |= ACC_DONT_SORT_ARTICLES;
  186.  
  187.     return access_mode;
  188. }
  189.  
  190. export group_header *jump_to_group = NULL;
  191. export int enter_last_read_mode = 1;
  192.  
  193. static group_header *last_group_maint(last, upd)
  194. group_header *last;
  195. int upd;
  196. {
  197.     group_header *gh;
  198.     FILE *f;
  199.     char *lg_file;
  200.     char buf[256], *cp;
  201.  
  202.     lg_file = relative(nn_directory, "NEXTG");
  203.     if (upd) {
  204.     if (last == NULL)
  205.         unlink(lg_file);
  206.     else {
  207.         f = open_file(lg_file, OPEN_CREATE | MUST_EXIST);
  208.         fprintf(f, "%s\n", last->group_name);
  209.         fclose(f);
  210.     }
  211.     return NULL;
  212.     }
  213.  
  214.     if (enter_last_read_mode == 0) goto none;
  215.  
  216.     f = open_file(lg_file, OPEN_READ);
  217.     if (f == NULL) goto none;
  218.     
  219.     gh = NULL;
  220.     if (fgets(buf, 256, f)) {
  221.     if ((cp = strchr(buf, NL))) *cp = NUL;
  222.     gh = lookup(buf);
  223.     }
  224.     fclose(f);
  225.  
  226.     if (gh == NULL || gh == last || !(gh->group_flag & G_SEQUENCE))
  227.     goto none;
  228.     
  229.     switch (enter_last_read_mode) {
  230.      case 1:        /* confirm if unread, skip if read */
  231.     if (gh->unread_count == 0) goto none;
  232.      case 2:        /* confirm any case */
  233.     prompt_line = Lines-1;
  234.     prompt("Enter %s (%ld unread)? ", gh->group_name, gh->unread_count);
  235.     if (!yes(0)) goto none;
  236.     break;
  237.      case 3:        /* enter uncond if unread */
  238.     if (gh->unread_count == 0) goto none;
  239.      case 4:        /* enter uncond */
  240.     break;
  241.     }
  242.     return gh;
  243.  none:
  244.     return last;
  245. }
  246.  
  247. static int
  248. read_news(access_mode, mask)
  249. flag_type access_mode;
  250. char *mask;
  251. {
  252.     register group_header *gh, *prev, *tmp, *after_loop;
  253.     flag_type group_mode;
  254.     int menu_cmd;
  255.     int must_clear = 0, did_jump = 0;
  256.     group_header *last_group_read = NULL;
  257.  
  258.     prev = group_sequence;
  259.     gh = group_sequence;
  260.     after_loop = NULL;
  261.  
  262.     if (access_mode == 0 && !also_read_articles) {
  263.     gh = last_group_maint(gh, 0);
  264.     did_jump = gh != group_sequence;
  265.     m_invoke(-2);
  266.     }
  267.  
  268.     for (;;) {
  269.     group_mode = access_mode;
  270.     
  271.     if (s_hangup) break;
  272.  
  273.     if (gh == NULL) {
  274.         if (after_loop != NULL) {
  275.         gh = after_loop;
  276.         after_loop = NULL;
  277.         if (gh->unread_count <= 0)
  278.             group_mode |= ACC_ORIG_NEWSRC;
  279.         goto enter_direct;
  280.         }
  281.  
  282.         if (did_jump) {
  283.         did_jump = 0;
  284.         gh = group_sequence;
  285.         continue;
  286.         }
  287.  
  288.         if (must_clear && conf_auto_quit) {
  289.         prompt("\1LAST GROUP READ.  QUIT NOW?\1");
  290.         switch (yes(1)) {
  291.          case 1:
  292.             break;
  293.          case 0:
  294.             gh = group_sequence;
  295.          default:
  296.             after_loop = prev;
  297.             continue;
  298.         }
  299.         }
  300.         last_group_read = NULL;
  301.         break;
  302.     }
  303.  
  304.     if (gh->group_flag & G_UNSUBSCRIBED) {
  305.         if (!also_unsub_groups) {
  306.         gh = gh->next_group;
  307.         continue;
  308.         }
  309.     } else
  310.         if (!also_read_articles && gh->unread_count <= 0) {
  311.         gh = gh->next_group;
  312.         continue;
  313.         }
  314.  
  315.      enter_direct:
  316.  
  317.     free_memory();
  318.  
  319.     if (gh->group_flag & G_FOLDER) {
  320.         menu_cmd = folder_menu(gh->group_name, 0);
  321.         if (menu_cmd == ME_NO_REDRAW) {
  322.         menu_cmd = ME_NO_ARTICLES;
  323.         gh->last_db_article = 0;
  324.         }
  325.     } else {
  326.         group_mode |= setup_access();
  327.         if (group_mode & ACC_ORIG_NEWSRC)
  328.         gh->last_article = gh->first_article;
  329.         
  330.         menu_cmd = group_menu(gh, (article_number)(-1), group_mode, mask, menu);
  331.         group_mode = access_mode;
  332.     }
  333.  
  334.     if (menu_cmd != ME_NO_ARTICLES) {
  335.         last_group_read = gh;
  336.         after_loop = NULL;
  337.         must_clear++;
  338.     }
  339.  
  340.     switch (menu_cmd) {
  341.  
  342.      case ME_QUIT:    /* or jump */
  343.         if (!jump_to_group) goto out;
  344.  
  345.         prev = jump_to_group;
  346.         jump_to_group = NULL;
  347.         did_jump = 1;
  348.         /* fall thru */
  349.  
  350.      case ME_PREV:
  351.         tmp = gh;
  352.         gh = prev;
  353.         prev = tmp;
  354.         if (gh->unread_count <= 0)
  355.         group_mode |= ACC_ORIG_NEWSRC;
  356.         else if (prev_also_read)
  357.         group_mode |= ACC_MERGED_NEWSRC;
  358.         goto enter_direct;
  359.  
  360.      case ME_NEXT:
  361.         prev = gh;
  362.         /* fall thru */
  363.  
  364.      case ME_NO_ARTICLES:
  365.         if (gh->group_flag & G_MERGE_HEAD) {
  366.         do gh = gh->next_group;
  367.             while (gh && (gh->group_flag & G_MERGE_SUB));
  368.         } else
  369.         gh = gh->next_group;
  370.         continue;
  371.     }
  372.     }
  373.  
  374.  out:
  375.     if (access_mode == 0 && !also_read_articles)
  376.     last_group_maint(last_group_read, 1);
  377.  
  378.     return must_clear;
  379. }
  380.  
  381.  
  382. static void
  383. catch_up()
  384. {
  385.     register group_header *gh;
  386.     char answer1[50];
  387.     int mode, must_help;
  388.     flag_type access_mode;
  389.  
  390.     access_mode = setup_access();
  391.     
  392.     prt_unread("\nCatch-up on %u ? (auto)matically (i)nteractive ");
  393.     fl;
  394.     mode = 0;
  395.  
  396.     if (gets(answer1)) {
  397.     if (strncmp(answer1, "auto", 4) == 0) {
  398.         tprintf("\nUPDATING .newsrc FILE....");
  399.         fl;
  400.         mode = -1;
  401.     } else
  402.     if (*answer1 == 'i')
  403.         mode = 1;
  404.     }
  405.  
  406.     if (mode == 0) {
  407.     tprintf("\nNO UPDATE\n");
  408.     return;
  409.     }
  410.  
  411.     newsrc_update_freq = 9999;
  412.     must_help = novice;
  413.  
  414.     Loop_Groups_Sequence(gh) {
  415.  
  416.     if ((gh->group_flag & G_COUNTED) == 0) continue;
  417.  
  418.     if (mode < 0) {
  419.         update_rc_all(gh, 0);
  420.         continue;
  421.     }
  422.  
  423.      again:
  424.     if (must_help) {
  425.         tprintf("\n  y - mark all articles as read in current group\n");
  426.         tprintf("  n - do not update group\n");
  427.         tprintf("  r - read the group now\n");
  428.         tprintf("  U - unsubscribe to current group\n");
  429.         tprintf("  ? - this message\n");
  430.         tprintf("  q - quit\n\n");
  431.  
  432.         must_help = 0;
  433.     }
  434.  
  435.     tprintf("\rUpdate %s (%ld)? (ynrU?q) n\b", gh->group_name,
  436.            (long)(gh->last_db_article - gh->last_article));
  437.     fl;
  438.  
  439.     if (gets(answer1) == NULL || s_keyboard)
  440.         *answer1 = 'q';
  441.  
  442.     switch (*answer1) {
  443.  
  444.      case 'q':
  445.         tputc(NL);
  446.         tprintf("Update rest? (yn) n\b");
  447.         fl;
  448.         if (gets(answer1) == NULL || *answer1 != 'y')
  449.         return;
  450.  
  451.         mode = -1;
  452.         break;
  453.  
  454.      case NUL:
  455.      case 'n':
  456.         continue;
  457.  
  458.      case 'r':
  459.         nn_raw();
  460.         group_menu(gh, (article_number)(-1), access_mode, (char *)NULL, menu);
  461.         unset_raw();
  462.         clrdisp();
  463.         if (gh->unread_count > 0) goto again;
  464.         continue;
  465.  
  466.      case 'U':
  467.         update_rc_all(gh, 1);
  468.         continue;
  469.  
  470.      case 'y':
  471.         break;
  472.  
  473.      default:
  474.         must_help = 1;
  475.         goto again;
  476.     }
  477.  
  478.     update_rc_all(gh, 0);
  479.     }
  480.  
  481.     tprintf("DONE\n");
  482.  
  483.     flush_newsrc();
  484. }
  485.  
  486. export char *mail_box = NULL;
  487.  
  488. int
  489. unread_mail(t)
  490. time_t t;
  491. {
  492.     struct stat st;
  493.     static time_t next = 0;
  494.     static int any = 0;
  495.  
  496.     if (next > t) return any;
  497.  
  498.     next = t + 60;
  499.     any = 0;
  500.  
  501.     if (mail_box == NULL ||
  502.     stat(mail_box, &st) != 0 ||
  503.     st.st_size == 0 ||
  504.     st.st_mtime < st.st_atime) return 0;
  505.  
  506.     any = 1;
  507.  
  508.     return 1;
  509. }
  510.  
  511. #ifdef ACCOUNTING
  512. #ifndef STATISTICS
  513. #define STATISTICS 1
  514. #endif
  515. #define NEED_ACCOUNT
  516. #else
  517. #ifdef AUTHORIZE
  518. #define NEED_ACCOUNT
  519. #endif
  520. #endif
  521.  
  522. #ifdef STATISTICS
  523. static time_t usage_time = 0;
  524. static time_t last_tick = 0;
  525.  
  526. void
  527. stop_usage()
  528. {
  529.     last_tick = 0;
  530. }
  531.  
  532. time_t tick_usage()
  533. {
  534.     register time_t now;
  535.  
  536.     now = cur_time();
  537.  
  538.     /*
  539.      * We ignore ticks > 2 minutes because the user has probably
  540.      * just left the terminal inside nn and done something else
  541.      */
  542.     if (last_tick > (now - 120))
  543.     usage_time += now - last_tick;
  544.  
  545.     last_tick = now;
  546.     return now;
  547. }
  548.  
  549. void
  550. log_usage()
  551. {
  552. #ifdef ACCOUNTING
  553.     account('U', report_cost_on_exit);
  554. #else
  555.     if (usage_time < (STATISTICS * 60)) return; /* don't log short sessions */
  556.  
  557.     usage_time /= 60;
  558.     log_entry('U', "USAGE %d.%02d", usage_time/60, usage_time%60);
  559. #endif
  560. }
  561.  
  562. #else
  563. void
  564. stop_usage()
  565. {
  566. }
  567.  
  568. time_t tick_usage()
  569. {
  570.     return cur_time();
  571. }
  572.  
  573. void
  574. log_usage()
  575. {
  576. }
  577. #endif
  578.  
  579. #ifdef NEED_ACCOUNT
  580. account(option, report)
  581. char option;
  582. int report;
  583. {
  584.     char *args[10], **ap;
  585.     char buf1[16], buf2[16];
  586.     int ok;
  587.  
  588.     if (who_am_i != I_AM_NN && who_am_i != I_AM_POST) return 0;
  589.  
  590.     if (report) {
  591.     tputc(CR); clrline(); fl;
  592.     }
  593.  
  594.     ap = args;
  595.     *ap++ = "nnacct";
  596.     if (report) *ap++ = "-r";
  597. #ifdef STATISTICS
  598.     sprintf(buf1, "-%c%ld", option, (long)usage_time/60);
  599. #else
  600.     sprintf(buf1, "-%c0", option);
  601. #endif
  602.     *ap++ = buf1;
  603.     sprintf(buf2, "-W%d", who_am_i);
  604.     *ap++ = buf2;
  605.     *ap++ = NULL;
  606.     ok = execute(relative(bin_directory, "nnacct"), args, 0);
  607.     if (option == 'U' && report) tputc(NL);
  608.     return ok;
  609. }
  610. #endif
  611.  
  612. /* this will go into emacs_mode.c when it is completed someday */
  613.  
  614. void
  615. emacs_mode()
  616. {
  617.     tprintf("EMACS MODE IS NOT SUPPORTED YET.\n");
  618. }
  619.  
  620.  
  621. static int
  622. do_nnspew()
  623. {
  624.     register group_header *gh;
  625.     int ix;
  626.  
  627.     ix = 0;
  628.     Loop_Groups_Header(gh) {
  629.     if (gh->master_flag & M_IGNORE_GROUP) continue;
  630.     gh->preseq_index = ++ix;
  631.     }
  632.  
  633.     /* Only output each article once */
  634.     /* Must also use this mode when using nngrab! */
  635.  
  636.     seq_cross_filtering = 1;
  637.  
  638.     Loop_Groups_Header(gh) {
  639.     if (s_hangup) return 1;
  640.     if (gh->master_flag & M_IGNORE_GROUP) continue;
  641.     access_group(gh, gh->first_db_article, gh->last_db_article,
  642.              ACC_DONT_SORT_ARTICLES | ACC_ALSO_FULL_DIGEST |
  643.              ACC_SPEW_MODE, (char *)NULL);
  644.     }
  645.     return 0;
  646. }
  647.  
  648. static void
  649. prt_version()
  650. {
  651.     tprintf("Release %s\n  by Kim F. Storm, Peter Wemm, and Michael T Pins, 1996\n\n", version_id);
  652. }
  653.  
  654. int
  655. display_motd(check)
  656. int check;
  657. {
  658.     time_t last_motd, cur_motd;
  659.     char *dot_motd, motd[FILENAME];
  660.  
  661.     strcpy(motd, relative(lib_directory, "motd"));
  662.     cur_motd = file_exist(motd, (char *)NULL);
  663.     if (cur_motd == 0) return 0;
  664.  
  665.     if (!check) {
  666.     display_file(motd, CLEAR_DISPLAY | CONFIRMATION);
  667.     return 1;
  668.     }
  669.  
  670.     dot_motd = relative(nn_directory, ".motd");
  671.     last_motd = file_exist(dot_motd, (char *)NULL);
  672.  
  673.     if (last_motd >= cur_motd) return 0;
  674.  
  675.     unlink(dot_motd);
  676.     fclose(open_file(dot_motd, OPEN_CREATE|MUST_EXIST));
  677.  
  678.     clrdisp();
  679.  
  680.     so_printxy(0, 0, "Message of the day");
  681.     gotoxy(0, 2); prt_version();
  682.  
  683.     display_file(motd, CONFIRMATION);
  684.     return 1;
  685. }
  686.  
  687. static void
  688. do_db_check()
  689. {
  690.     time_t last_upd;
  691.  
  692. #ifdef NOV
  693.  
  694.     time_t active_time;
  695.  
  696.     if (use_nntp) return;
  697.  
  698.     active_time = file_exist(news_active, (char *)NULL);
  699.     if (active_time == 0)
  700.         return;            /* cannot stat/read/etc... */
  701.  
  702.     last_upd = (cur_time() - active_time) / (60 * 60);
  703.     if (last_upd < check_db_update)
  704.       return;
  705.     tprintf("Notice: no news has arrived for the last %ld hours\n", last_upd);
  706.  
  707. #else /* NOV */
  708.  
  709.     last_upd = (cur_time() - master.last_scan) / (60 * 60);
  710.     if (last_upd < check_db_update) return;
  711.     /* too old - but is nnmaster the culprit? */
  712.     if (master.last_scan == file_exist(news_active, (char *)NULL))
  713.       tprintf("Notice: no news has arrived for the last %ld hours\n", last_upd);
  714.     else
  715.       tprintf("Notice: nnmaster has not updated database in %ld hours\n", last_upd);
  716.  
  717. #endif /* NOV */
  718.  
  719.     sleep(3);
  720. }
  721.  
  722. void
  723. clean_group(gh)
  724. group_header *gh;
  725. {
  726. }
  727.  
  728. int
  729. main(argc, argv)
  730. int argc;
  731. char *argv[];
  732. {
  733.     int say_welcome = 0, cmd;
  734.     flag_type access_mode = 0;
  735.     char *mask = NULL;
  736.     initial_memory_break = (long)sbrk(0);
  737.  
  738. #ifdef USE_MALLOC_H
  739. #ifdef MALLOC_MAXFAST
  740.     mallopt(M_MXFAST, MALLOC_MAXFAST);
  741. #endif
  742. #ifdef MALLOC_FASTBLOCKS
  743.     mallopt(M_NLBLKS, MALLOC_FASTBLOCKS);
  744. #endif
  745. #ifdef MALLOC_GRAIN
  746.     mallopt(M_GRAIN, MALLOC_GRAIN);
  747. #endif
  748. #endif
  749.  
  750. #ifdef MALDEBUG
  751.     mal_debug(getenv("MALDEBUG") ? atoi(getenv("MALDEBUG")) : 0);
  752. #endif
  753.  
  754.     pname = program_name(argv);
  755.  
  756.     if (strcmp(pname, "nnadmin") == 0) {
  757.     who_am_i = I_AM_ADMIN;
  758.     } else
  759.     if (strcmp(pname, "nnemacs") == 0) {
  760.     who_am_i = I_AM_EMACS;
  761.     } else
  762.     if (strcmp(pname, "nncheck") == 0) {
  763.     who_am_i = I_AM_CHECK;
  764.     } else
  765.     if (strcmp(pname, "nntidy") == 0) {
  766.     who_am_i = I_AM_TIDY;
  767.     } else
  768.     if (strcmp(pname, "nngoback") == 0) {
  769.     who_am_i = I_AM_GOBACK;
  770.     } else
  771.     if (strcmp(pname, "nngrep") == 0) {
  772.     who_am_i = I_AM_GREP;
  773.     } else
  774.     if (strcmp(pname, "nnpost") == 0) {
  775.     who_am_i = I_AM_POST;
  776.     } else
  777.     if (strcmp(pname, "nnview") == 0) {
  778.     who_am_i = I_AM_VIEW;
  779.     } else
  780.     if (strcmp(pname, "nnbatch") == 0) {
  781.     who_am_i = I_AM_NN;
  782.     batch_mode = 1;
  783.     } else {
  784.     who_am_i = I_AM_NN;
  785.     }
  786. #ifdef NOV
  787. # ifdef NOV_DIRECTORY
  788.     if (who_am_i != I_AM_VIEW)
  789.     novartdir(NOV_DIRECTORY);
  790. # endif
  791. #endif
  792.  
  793.     if (who_am_i == I_AM_NN || (who_am_i == I_AM_ADMIN && argc == 1)) {
  794.     if (!batch_mode && !isatty(0)) {
  795.         if (who_am_i == I_AM_NN && argc == 2) {
  796.         if (strcmp(argv[1], "-SPEW") == 0) {
  797.             who_am_i = I_AM_SPEW;
  798.             init_global();
  799.             goto nnspew;
  800.         }
  801.         }
  802.  
  803.         fprintf(stderr, "Input is not a tty\n");
  804.         exit(1);
  805.     }
  806.     }
  807.  
  808. #ifdef AUTHORIZE
  809.     init_execute();
  810.     if (cmd = account('P', 0)) {
  811.     switch (cmd) {
  812.      case 1:
  813.         if (who_am_i == I_AM_POST) {
  814.         tprintf("You are not authorized to post news\n");
  815.         exit(41);
  816.         }
  817.         /* ok_to_post = 0; */
  818.         cmd = 0;
  819.         break;
  820.      case 2:
  821.         tprintf("You are not authorized to read news\n");
  822.         break;
  823.      case 3:
  824.         tprintf("You cannot read news at this time\n");
  825.         break;
  826.      case 4:
  827.         tprintf("Your news reading quota is exceeded\n");
  828.         break;
  829.      default:
  830.         tprintf("Bad authorization -- reason %d\n", cmd);
  831.         break;
  832.     }
  833.     if (cmd) exit(40 + cmd);
  834.     }
  835. #endif
  836.  
  837.     if ((say_welcome = init_global()) < 0)
  838.     nn_exitmsg(1, "%s: nn has not been invoked to initialize user files", pname);
  839.  
  840. #ifdef NNTP
  841.     nntp_check();
  842. #endif
  843.  
  844.     init_key_map();
  845. #ifndef AUTHORIZE
  846.     init_execute();
  847. #endif
  848.     init_macro();
  849.  
  850.  nnspew:
  851.  
  852.     if (who_am_i != I_AM_VIEW)
  853.     open_master(OPEN_READ);
  854.  
  855.     switch (who_am_i) {
  856.  
  857.      case I_AM_VIEW:
  858.     /*FALLTHROUGH*/
  859.  
  860.      case I_AM_NN:
  861.     visit_init_file(0, argv[1]);
  862.     init_term(1);
  863.  
  864.     if (say_welcome) {
  865.         first_time_user = 1;
  866.         display_file("adm.welcome", CLEAR_DISPLAY | CONFIRMATION);
  867.         clrdisp();
  868.     }
  869.  
  870.  
  871.     if (show_motd_on_entry)
  872.         if (display_motd(1))
  873.         silent = 1;
  874.     
  875.     init_answer();
  876.  
  877.     group_name_args =
  878.         parse_options(argc, argv, (char *)NULL, nn_options,
  879.               " [group | [+]folder]...");
  880.  
  881.     if (also_read_articles) {
  882.         if (article_limit < 0)
  883.         article_limit = also_read_articles;
  884.         do_kill_handling = 0;
  885.         no_update++;
  886.     }
  887.  
  888.     if (match_subject) {
  889.         mask = match_subject;
  890.         access_mode = ACC_ON_SUBJECT;
  891.     } else if (match_sender) {
  892.         mask = match_sender;
  893.         access_mode = ACC_ON_SENDER;
  894.     } else {
  895.         mask = NULL;
  896.         access_mode = 0;
  897.     }
  898.  
  899.     if (mask) {
  900.         if (case_fold_search) fold_string(mask);
  901.         no_update++;
  902.         do_kill_handling = 0;
  903.     }
  904.  
  905.     if (nngrab_mode) {
  906.         seq_cross_filtering = 1;
  907.         hex_group_args = 1;
  908.         no_update = 1;
  909.     }
  910.  
  911.     if (merged_menu) {
  912.         no_update++;
  913.     }
  914.  
  915.     if (!no_update && group_name_args > 0)
  916.         no_update = only_folder_args(argv + 1);
  917.  
  918.     break;
  919.  
  920.      case I_AM_ADMIN:
  921.     if (argc == 1) {
  922.         init_term(1);
  923.         visit_init_file(0, (char *)NULL);
  924.     }
  925.     admin_mode(argv[1]);
  926.     nn_exit(0);
  927.  
  928.      case I_AM_CHECK:
  929.     init_term(0);
  930.     visit_init_file(0, (char *)NULL);
  931.     silent = 0;        /* override setting in init file */
  932.     group_name_args =
  933.         parse_options(argc, argv, (char *)NULL, check_options,
  934.               " [group]...");
  935.     no_update = 1;        /* don't update .newsrc and LAST */
  936.     break;
  937.  
  938.      case I_AM_EMACS:
  939.     silent = 1;
  940.     break;
  941.  
  942.      case I_AM_TIDY:
  943.     init_term(0);
  944.     visit_init_file(0, (char *)NULL);
  945.     group_name_args = opt_nntidy(argc, argv);
  946.     break;
  947.  
  948.      case I_AM_GOBACK:
  949.     init_term(0);
  950.     visit_init_file(0, (char *)NULL);
  951.     group_name_args = opt_nngoback(argc, &argv);
  952.     break;
  953.  
  954.      case I_AM_GREP:
  955.     init_term(0);
  956.     visit_init_file(0, (char *)NULL);
  957.     opt_nngrep(argc, argv);
  958.     silent = 1;
  959.     no_update = 1;
  960.     break;
  961.  
  962.      case I_AM_POST:
  963.     do_nnpost(argc, argv);
  964.     nn_exit(0);
  965.  
  966.      case I_AM_SPEW:
  967.     if (proto_lock(I_AM_SPEW, PL_SET) == 0) {
  968.         cmd = do_nnspew();
  969.         proto_lock(I_AM_SPEW, PL_CLEAR);
  970.     } else
  971.         cmd = 1;    /* don't interfere with other nnspew */
  972.     nn_exit(cmd);
  973.     }
  974.  
  975.     if (!silent && who_am_i != I_AM_CHECK)
  976.     prt_version();
  977.  
  978.     if (who_am_i == I_AM_VIEW) {
  979.     named_group_sequence(argv + 1);
  980.     count_unread_articles();
  981.     if (read_news(access_mode, mask))
  982.         clrdisp();
  983.     nn_exit(0);
  984.     }
  985.  
  986.     if (nn_locked()) nn_exit(2);
  987.  
  988.     visit_rc_file();
  989.  
  990.     if (group_name_args > 0)
  991.     named_group_sequence(argv + 1);
  992.     else
  993.     normal_group_sequence();
  994.  
  995.     if (who_am_i != I_AM_TIDY && who_am_i != I_AM_GOBACK)
  996.     count_unread_articles();
  997.  
  998.     switch (who_am_i) {
  999.  
  1000.      case I_AM_EMACS:
  1001.     prt_unread("%U %G\n");
  1002.     emacs_mode();
  1003.     break;
  1004.  
  1005.      case I_AM_CHECK:
  1006.     if (report_number_of_articles) {
  1007.         prt_unread("%U");
  1008.         break;
  1009.     }
  1010.  
  1011.     if (check_message_format) {
  1012.         if (unread_articles || !silent)
  1013.         prt_unread(check_message_format);
  1014.     } else
  1015.     if (!silent) {
  1016.         if (unread_articles || report_number_of_articles)
  1017.         prt_unread("There %i %u in %g\n");
  1018.         else
  1019.         prt_unread((char *)NULL);
  1020.     }
  1021.  
  1022.     nn_exit( unread_articles ? 0 : 99 );
  1023.     /*NOTREACHED*/
  1024.  
  1025.      case I_AM_TIDY:
  1026.     do_tidy_newsrc();
  1027.     break;
  1028.  
  1029.      case I_AM_GOBACK:
  1030.     do_goback();
  1031.     break;
  1032.  
  1033.      case I_AM_NN:
  1034.     if (check_db_update)
  1035.         do_db_check();
  1036.  
  1037.     if (unread_articles == 0 &&
  1038.         group_name_args == 0 &&
  1039.         !also_read_articles &&
  1040.         !prompt_for_group) {
  1041.         if (!silent) prt_unread((char *)NULL);
  1042.         break;
  1043.     }
  1044.  
  1045.     if (do_kill_handling)
  1046.         do_kill_handling = init_kill();
  1047.  
  1048.     if (prompt_for_group) {
  1049.  
  1050.         if (mask != NULL)
  1051.         nn_exitmsg(1, "Cannot use -s/-n with -g\n\r");
  1052.         
  1053.         also_cross_postings = 1;
  1054.         do {
  1055.         nn_raw();
  1056.         clrdisp();
  1057.         current_group = NULL;
  1058.         prompt_line = 2;
  1059.         cmd = goto_group(K_GOTO_GROUP, (article_header *)NULL, setup_access());
  1060.         
  1061.         if (cmd == ME_NO_REDRAW) sleep(2);
  1062.         } while (repeat_group_query && cmd != ME_QUIT && cmd != ME_NO_REDRAW);
  1063.         clrdisp();
  1064.         unset_raw();
  1065.         break;
  1066.     }
  1067.  
  1068.     if (!no_update && article_limit == 0) {
  1069.         catch_up();
  1070.         break;
  1071.     }
  1072.  
  1073.     if (merged_menu) {
  1074.         merge_and_read(access_mode | setup_access(), mask);
  1075.         clrdisp();
  1076.         break;
  1077.     }
  1078.  
  1079.     if (read_news(access_mode, mask)) {
  1080.         clrdisp();
  1081.  
  1082.         if (master.db_lock[0])
  1083.         tprintf("Database has been locked:\n%s\n", master.db_lock);
  1084.  
  1085.         if (!also_read_articles &&
  1086.         unread_articles > 0 &&
  1087.         !silent && group_name_args == 0)
  1088.         prt_unread("There %i still %u in %g\n\n\r");
  1089.         break;
  1090.     }
  1091.     gotoxy(0,Lines-1);
  1092.     if (group_name_args == 0)
  1093.         tprintf("No News (is good news)\n");
  1094.     else
  1095.         tprintf("\r\n");
  1096.     break;
  1097.  
  1098.      case I_AM_GREP:
  1099.     do_grep(argv+1);
  1100.     break;
  1101.     }
  1102.  
  1103.     nn_exit(0);
  1104.     /*NOTREACHED*/
  1105.     return 0;
  1106. }
  1107.  
  1108. /*
  1109.  * nn_exit() --- called whenever a program exits.
  1110.  */
  1111.  
  1112. void
  1113. nn_exit(n)
  1114. int n;
  1115. {
  1116.     static int loop = 0;
  1117.  
  1118.     if (loop) exit(n);
  1119.     loop++;
  1120.  
  1121.     visual_off();
  1122.  
  1123. #ifdef NNTP
  1124.     nntp_cleanup();
  1125. #endif /* NNTP */
  1126.     close_master();
  1127.     flush_newsrc();
  1128.  
  1129.     if (who_am_i == I_AM_NN)
  1130.     log_usage();
  1131.  
  1132.     if (must_unlock)
  1133.     proto_lock(I_AM_NN, PL_CLEAR);
  1134.  
  1135. #if 0
  1136.     malloc_verify(0);
  1137.     malloc_shutdown();
  1138. #endif
  1139.     exit(n);
  1140. }
  1141.