"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.4/src/main.c" (20 Nov 2019, 26947 Bytes) of package /linux/misc/tin-2.4.4.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4.3_vs_2.4.4.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : main.c
    4  *  Author    : I. Lea & R. Skrenta
    5  *  Created   : 1991-04-01
    6  *  Updated   : 2019-07-16
    7  *  Notes     :
    8  *
    9  * Copyright (c) 1991-2020 Iain Lea <iain@bricbrac.de>, Rich Skrenta <skrenta@pbm.com>
   10  * All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  *
   16  * 1. Redistributions of source code must retain the above copyright notice,
   17  *    this list of conditions and the following disclaimer.
   18  *
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  *
   23  * 3. Neither the name of the copyright holder nor the names of its
   24  *    contributors may be used to endorse or promote products derived from
   25  *    this software without specific prior written permission.
   26  *
   27  * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 
   41 #ifndef TIN_H
   42 #   include "tin.h"
   43 #endif /* !TIN_H */
   44 #ifndef TCURSES_H
   45 #   include "tcurses.h"
   46 #endif /* !TCURSES_H */
   47 #ifndef VERSION_H
   48 #   include "version.h"
   49 #endif /* !VERSION_H */
   50 
   51 signed long int read_newsrc_lines = -1;
   52 
   53 static char **cmdargs;
   54 static int num_cmdargs;
   55 static int max_cmdargs;
   56 
   57 static t_bool catchup = FALSE;      /* mark all arts read in all subscribed groups */
   58 static t_bool update_index = FALSE;     /* update local overviews */
   59 static t_bool check_any_unread = FALSE; /* print/return status if any unread */
   60 static t_bool mail_news = FALSE;        /* mail all arts to specified user */
   61 static t_bool save_news = FALSE;        /* save all arts to savedir structure */
   62 static t_bool start_any_unread = FALSE; /* only start if unread news */
   63 
   64 
   65 /*
   66  * Local prototypes
   67  */
   68 static void create_mail_save_dirs(void);
   69 static void read_cmd_line_options(int argc, char *argv[]);
   70 static void show_intro_page(void);
   71 static void update_index_files(void);
   72 static void usage(char *theProgname);
   73 
   74 
   75 /*
   76  * OK lets start the ball rolling...
   77  */
   78 int
   79 main(
   80     int argc,
   81     char *argv[])
   82 {
   83     int count, start_groupnum;
   84     int num_cmd_line_groups = 0;
   85     t_bool tmp_no_write;
   86 
   87     cmd_line = TRUE;
   88 
   89     /* initialize locale support */
   90 #if defined(HAVE_SETLOCALE) && !defined(NO_LOCALE)
   91     if (setlocale(LC_ALL, "")) {
   92 #   ifdef ENABLE_NLS
   93         bindtextdomain(NLS_TEXTDOMAIN, LOCALEDIR);
   94         textdomain(NLS_TEXTDOMAIN);
   95 #   endif /* ENABLE_NLS */
   96     } else
   97         error_message(4, txt_error_locale);
   98 #endif /* HAVE_SETLOCALE && !NO_LOCALE */
   99 
  100     /*
  101      * determine local charset
  102      */
  103 #ifndef NO_LOCALE
  104     {
  105         const char *p;
  106 
  107         if ((p = tin_nl_langinfo(CODESET)) != NULL) {
  108             if (!strcasecmp(p, "ANSI_X3.4-1968"))
  109                 STRCPY(tinrc.mm_local_charset, "US-ASCII");
  110             else
  111                 STRCPY(tinrc.mm_local_charset, p);
  112         }
  113     }
  114 #endif /* !NO_LOCALE */
  115     /* always set a default value */
  116     if (!*tinrc.mm_local_charset)
  117         STRCPY(tinrc.mm_local_charset, "US-ASCII");
  118 
  119     set_signal_handlers();
  120 
  121     debug = 0;  /* debug OFF */
  122 
  123     tin_progname = my_malloc(strlen(argv[0]) + 1);
  124     base_name(argv[0], tin_progname);
  125 
  126 #ifdef NNTP_ONLY
  127     read_news_via_nntp = TRUE;
  128 #else
  129     /*
  130      * If called as rtin, read news remotely via NNTP
  131      */
  132     if (tin_progname[0] == 'r') {
  133 #   ifdef NNTP_ABLE
  134         read_news_via_nntp = TRUE;
  135 #   else
  136         error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  137         free(tin_progname);
  138         giveup();
  139 #   endif /* NNTP_ABLE */
  140     }
  141 #endif /* NNTP_ONLY */
  142 
  143     /*
  144      * Set up initial array sizes, char *'s: homedir, newsrc, etc.
  145      */
  146     init_alloc();
  147     hash_init();
  148     init_selfinfo();
  149     init_group_hash();
  150 
  151     /*
  152      * Set cCOLS temporarily to trim (localized) messages
  153      * It does not matter if this value is greater than the actual
  154      * terminal size
  155      *
  156      * cCOLS will be set later to the real terminal width
  157      */
  158     cCOLS = 80;
  159 
  160     /*
  161      * Process envargs & command line options
  162      * These override the configured in values
  163      */
  164     read_cmd_line_options(argc, argv);
  165 
  166     /* preinit keybindings if interactive */
  167     if (!batch_mode)
  168         setup_default_keys();
  169 
  170     /*
  171      * Read user local & global config files
  172      * These override the compiled in defaults
  173      *
  174      * must be called before setup_screen()
  175      */
  176     read_config_file(global_config_file, TRUE);
  177     read_config_file(local_config_file, FALSE);
  178 
  179     tmp_no_write = no_write; /* keep no_write */
  180     no_write = TRUE;        /* don't allow any writing back during startup */
  181 
  182     if (!batch_mode) {
  183 #ifndef USE_CURSES
  184         if (!get_termcaps()) {
  185             error_message(2, _(txt_screen_init_failed), tin_progname);
  186             free_all_arrays();
  187             giveup();
  188         }
  189 #endif /* !USE_CURSES */
  190 
  191         /*
  192          * Init curses emulation
  193          */
  194         if (!InitScreen()) {
  195             error_message(2, _(txt_screen_init_failed), tin_progname);
  196             free_all_arrays();
  197             giveup();
  198         }
  199 
  200         EndInverse();
  201 
  202         /*
  203          * This depends on various things in tinrc
  204          */
  205         setup_screen();
  206     }
  207 
  208     if (!batch_mode || verbose)
  209         wait_message(0, "%s\n", cvers);
  210 
  211     /*
  212      * Connect to nntp server?
  213      */
  214     if (!nntp_server || !*nntp_server)
  215         nntp_server = getserverbyfile(NNTP_SERVER_FILE);
  216     if (read_news_via_nntp && !read_saved_news && nntp_open()) {
  217         nntp_close(FALSE);
  218         free_all_arrays();
  219         giveup();
  220     }
  221 
  222     read_server_config();
  223 
  224     /*
  225      * exit early - unfortunately we can't do that in read_cmd_line_options()
  226      * as nntp_caps.over_cmd is set in nntp_open()
  227      *
  228      * TODO: does the logic make sense? what
  229      * if (update_index && !nntp_caps.over_cmd && !tinrc.cache_overview_files)
  230      * no error message? why?
  231      */
  232     if (update_index && nntp_caps.over_cmd && !tinrc.cache_overview_files) {
  233         error_message(2, _(txt_batch_update_unavail), tin_progname, print_boolean(tinrc.cache_overview_files));
  234         free_all_arrays();
  235         giveup();
  236     }
  237 
  238     /*
  239      * Check if overview indexes contain Xref: lines
  240      */
  241 #ifdef NNTP_ABLE
  242     if ((read_news_via_nntp && nntp_caps.over_cmd) || !read_news_via_nntp)
  243 #endif /* NNTP_ABLE */
  244         xref_supported = overview_xref_support();
  245 
  246     /*
  247      * avoid empty regexp, we also need to do this in batch_mode
  248      * as read_overview() calls eat_re() which uses a regexp to
  249      * modify the subject *sigh*
  250      */
  251     postinit_regexp();
  252 
  253     if (!(batch_mode || post_postponed_and_exit)) {
  254         /*
  255          * Read user specific keybindings and input history
  256          */
  257         wait_message(0, _(txt_reading_keymap_file));
  258         read_keymap_file();
  259         read_input_history_file();
  260 
  261         /*
  262          * Load the mail & news active files into active[]
  263          *
  264          * create_save_active_file cannot write to active.save
  265          * if no_write != FALSE, so restore original value temporarily
  266          */
  267         if (read_saved_news) {
  268             no_write = tmp_no_write;
  269             create_save_active_file();
  270             no_write = TRUE;
  271         }
  272     }
  273 
  274 #ifdef HAVE_MH_MAIL_HANDLING
  275     read_mail_active_file();
  276 #endif /* HAVE_MH_MAIL_HANDLING */
  277 
  278     /*
  279      * Initialise active[] and add new newsgroups to start of my_group[]
  280      * also reads global/local attributes
  281      */
  282     selmenu.max = 0;
  283     /*
  284      * we need to restore the original no_write mode to be able to handle
  285      * $AUTOSUBSCRIBE groups
  286      */
  287     no_write = tmp_no_write;
  288     read_attributes_file(TRUE);
  289     read_attributes_file(FALSE);
  290     start_groupnum = read_news_active_file();
  291 #ifdef DEBUG
  292     debug_print_active();
  293 #endif /* DEBUG */
  294 
  295     /*
  296      * Read in users filter preferences file. This has to be done before
  297      * quick post because the filters might be updated.
  298      */
  299     read_filter_file(filter_file);
  300 
  301     no_write = TRUE;
  302 #ifdef DEBUG
  303     debug_print_filters();
  304 #endif /* DEBUG */
  305 
  306     /*
  307      * Preloads active[] with command line groups. They will follow any
  308      * new newsgroups
  309      */
  310     if (!post_postponed_and_exit)
  311         num_cmd_line_groups = read_cmd_line_groups();
  312 
  313     /*
  314      * Quick post an article and exit if -w or -o specified
  315      */
  316     if (post_article_and_exit || post_postponed_and_exit) {
  317         no_write = tmp_no_write; /* restore original value */
  318         quick_post_article(post_postponed_and_exit, num_cmd_line_groups);
  319         wait_message(2, _(txt_exiting));
  320         no_write = TRUE; /* disable newsrc updates */
  321         tin_done(EXIT_SUCCESS, NULL);
  322     }
  323 
  324     /* TODO: replace hard coded key-name in txt_info_postponed */
  325     if ((count = count_postponed_articles()))
  326         wait_message(3, _(txt_info_postponed), count, PLURAL(count, txt_article));
  327 
  328     /*
  329      * Read text descriptions for mail and/or news groups
  330      */
  331     if (show_description && !batch_mode) {
  332         no_write = tmp_no_write; /* restore original value */
  333         read_descriptions(TRUE);
  334         no_write = TRUE; /* disable newsrc updates */
  335     }
  336 
  337     /* what about "if (!no_write)" here? */
  338     create_mail_save_dirs();
  339     if (created_rcdir) /* first start */
  340         write_config_file(local_config_file);
  341 
  342     if (!tmp_no_write)  /* do not (over)write oldnewsrc with -X */
  343         backup_newsrc();
  344 
  345     /*
  346      * Load my_groups[] from the .newsrc file. We append these groups to any
  347      * new newsgroups and command line newsgroups already loaded. Also does
  348      * auto-subscribe to groups specified in /usr/lib/news/subscriptions
  349      * locally or via NNTP if reading news remotely (LIST SUBSCRIPTIONS)
  350      */
  351     /*
  352      * TODO:
  353      * if (num_cmd_line_groups != 0 && check_any_unread)
  354      * don't read newsrc.
  355      * This makes -Z handle command line newsgroups. Test & document
  356      */
  357     read_newsrc_lines = read_newsrc(newsrc, FALSE);
  358     no_write = tmp_no_write; /* restore old value */
  359 
  360     /*
  361      * We have to show all groups with command line groups
  362      */
  363     if (num_cmd_line_groups)
  364         tinrc.show_only_unread_groups = FALSE;
  365     else
  366         toggle_my_groups(NULL);
  367 
  368     /*
  369      * Check/start if any new/unread articles
  370      */
  371     if (check_any_unread)
  372         tin_done(check_start_save_any_news(CHECK_ANY_NEWS, catchup), NULL);
  373 
  374     if (start_any_unread) {
  375         batch_mode = TRUE;          /* Suppress some unwanted on-screen garbage */
  376         if ((start_groupnum = check_start_save_any_news(START_ANY_NEWS, catchup)) == -1) {
  377             batch_mode = FALSE;
  378             tin_done(EXIT_SUCCESS, NULL);
  379         }
  380         batch_mode = FALSE;
  381     }
  382 
  383     /*
  384      * Mail any new articles to specified user
  385      * or
  386      * Save any new articles to savedir structure for later reading
  387      *
  388      * TODO: should we temporarily set
  389      *       getart_limit=-1,thread_articles=0,sort_article_type=0
  390      *       for speed reasons?
  391      */
  392     if (mail_news || save_news) {
  393         check_start_save_any_news(mail_news ? MAIL_ANY_NEWS : SAVE_ANY_NEWS, catchup);
  394         tin_done(EXIT_SUCCESS, NULL);
  395     }
  396 
  397     /*
  398      * Catchup newsrc file (-c option)
  399      */
  400     if (batch_mode && catchup && !update_index) {
  401         catchup_newsrc_file();
  402         tin_done(EXIT_SUCCESS, NULL);
  403     }
  404 
  405     /*
  406      * Update index files (-u option), also does catchup if requested
  407      */
  408     if (update_index)
  409         update_index_files();
  410 
  411     /*
  412      * the code below this point can't be reached in batch mode
  413      */
  414 
  415     /*
  416      * If first time print welcome screen
  417      */
  418     if (created_rcdir)
  419         show_intro_page();
  420 
  421 #ifdef XFACE_ABLE
  422     if (tinrc.use_slrnface && !batch_mode)
  423         slrnface_start();
  424 #endif /* XFACE_ABLE */
  425 
  426 #ifdef USE_CURSES
  427     /* Turn scrolling off now the startup messages have been displayed */
  428     scrollok(stdscr, FALSE);
  429 #endif /* USE_CURSES */
  430 
  431     /*
  432      * Work loop
  433      */
  434     selection_page(start_groupnum, num_cmd_line_groups);
  435     /* NOTREACHED */
  436     return 0;
  437 }
  438 
  439 
  440 /*
  441  * process command line options
  442  * [01235789beEFijJkKLOtTyY] are unused
  443  * [W] is reserved
  444  * [BCPU] have been in use at some time, but now are unused:
  445  *   B BBS mode (M_AMIGA only)
  446  *   C count articles
  447  *   P purge group index files of articles that no longer exist
  448  *   U update index files in background
  449  */
  450 #define OPTIONS "46aAcdD:f:g:G:hHI:lm:M:nNop:qQrRs:SuvVwxXzZ"
  451 
  452 static void
  453 read_cmd_line_options(
  454     int argc,
  455     char *argv[])
  456 {
  457     int ch;
  458     t_bool newsrc_set = FALSE;
  459 
  460     envargs(&argc, &argv, "TINRC");
  461 
  462     while ((ch = getopt(argc, argv, OPTIONS)) != -1) {
  463         switch (ch) {
  464 
  465             case '4':
  466 #if defined(NNTP_ABLE) && defined(INET6)
  467                 force_ipv4 = TRUE;
  468                 read_news_via_nntp = TRUE;
  469 #else
  470 #   ifdef NNTP_ABLE
  471                 error_message(2, _(txt_option_not_enabled), "-DENABLE_IPV6");
  472 #   else
  473                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  474 #   endif /* NNTP_ABLE */
  475                 free_all_arrays();
  476                 giveup();
  477                 /* keep lint quiet: */
  478                 /* NOTREACHED */
  479 #endif /* NNTP_ABLE && INET6 */
  480                 break;
  481 
  482             case '6':
  483 #if defined(NNTP_ABLE) && defined(INET6)
  484                 force_ipv6 = TRUE;
  485                 read_news_via_nntp = TRUE;
  486 #   else
  487 #   ifdef NNTP_ABLE
  488                 error_message(2, _(txt_option_not_enabled), "-DENABLE_IPV6");
  489 #   else
  490                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  491 #   endif /* NNTP_ABLE */
  492                 free_all_arrays();
  493                 giveup();
  494                 /* keep lint quiet: */
  495                 /* NOTREACHED */
  496 #endif /* NNTP_ABLE && INET6 */
  497                 break;
  498 
  499             case 'a':
  500 #ifdef HAVE_COLOR
  501                 cmdline.args |= CMDLINE_USE_COLOR;
  502 #else
  503                 error_message(2, _(txt_option_not_enabled), "-DHAVE_COLOR");
  504                 free_all_arrays();
  505                 giveup();
  506                 /* keep lint quiet: */
  507                 /* NOTREACHED */
  508 #endif /* HAVE_COLOR */
  509                 break;
  510 
  511             case 'A':
  512 #ifdef NNTP_ABLE
  513                 force_auth_on_conn_open = TRUE;
  514                 read_news_via_nntp = TRUE;
  515 #else
  516                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  517                 free_all_arrays();
  518                 giveup();
  519                 /* keep lint quiet: */
  520                 /* NOTREACHED */
  521 #endif /* NNTP_ABLE */
  522                 break;
  523 
  524             case 'c':
  525                 batch_mode = TRUE;
  526                 catchup = TRUE;
  527                 break;
  528 
  529             case 'd':
  530                 show_description = FALSE;
  531                 break;
  532 
  533             case 'D':       /* debug mode */
  534 #ifdef DEBUG
  535                 debug = atoi(optarg) & 0xff;
  536                 debug_delete_files();
  537 #else
  538                 error_message(2, _(txt_option_not_enabled), "-DDEBUG");
  539                 free_all_arrays();
  540                 giveup();
  541                 /* keep lint quiet: */
  542                 /* NOTREACHED */
  543 #endif /* DEBUG */
  544                 break;
  545 
  546             case 'f':   /* newsrc file */
  547                 my_strncpy(newsrc, optarg, sizeof(newsrc) - 1);
  548                 newsrc_set = TRUE;
  549                 break;
  550 
  551             case 'G':
  552                 cmdline.getart_limit = atoi(optarg);
  553                 cmdline.args |= CMDLINE_GETART_LIMIT;
  554                 break;
  555 
  556             case 'g':   /* select alternative NNTP-server, implies -r */
  557 #ifdef NNTP_ABLE
  558                 my_strncpy(cmdline.nntpserver, optarg, sizeof(cmdline.nntpserver) - 1);
  559                 cmdline.args |= CMDLINE_NNTPSERVER;
  560                 read_news_via_nntp = TRUE;
  561 #else
  562                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  563                 free_all_arrays();
  564                 giveup();
  565                 /* keep lint quiet: */
  566                 /* NOTREACHED */
  567 #endif /* NNTP_ABLE */
  568                 break;
  569 
  570             case 'H':
  571                 show_intro_page();
  572                 free_all_arrays();
  573                 exit(EXIT_SUCCESS);
  574                 /* keep lint quiet: */
  575                 /* FALLTHROUGH */
  576 
  577             case 'I':
  578                 my_strncpy(index_newsdir, optarg, sizeof(index_newsdir) - 1);
  579                 break;
  580 
  581             case 'l':
  582                 list_active = TRUE;
  583                 break;
  584 
  585             case 'm':
  586                 my_strncpy(cmdline.maildir, optarg, sizeof(cmdline.maildir) - 1);
  587                 cmdline.args |= CMDLINE_MAILDIR;
  588                 break;
  589 
  590             case 'M':   /* mail new news to specified user */
  591                 my_strncpy(mail_news_user, optarg, sizeof(mail_news_user) - 1);
  592                 mail_news = TRUE;
  593                 batch_mode = TRUE;
  594                 break;
  595 
  596             case 'n':
  597                 newsrc_active = TRUE;
  598                 break;
  599 
  600             case 'N':   /* mail new news to your posts */
  601                 my_strncpy(mail_news_user, userid, sizeof(mail_news_user) - 1);
  602                 mail_news = TRUE;
  603                 batch_mode = TRUE;
  604                 break;
  605 
  606             case 'o':   /* post postponed articles & exit */
  607 #ifndef NO_POSTING
  608                 /*
  609                  * TODO: autoposting currently does some screen output, so we
  610                  *       can't set batch_mode
  611                  */
  612                 post_postponed_and_exit = TRUE;
  613                 check_for_new_newsgroups = FALSE;
  614 #else
  615                 error_message(2, _(txt_option_not_enabled), "-UNO_POSTING");
  616                 free_all_arrays();
  617                 giveup();
  618                 /* keep lint quiet: */
  619                 /* NOTREACHED */
  620 #endif /* !NO_POSTING */
  621                 break;
  622 
  623             case 'p': /* implies -r */
  624 #ifdef NNTP_ABLE
  625                 read_news_via_nntp = TRUE;
  626                 if (atoi(optarg) != 0)
  627                     nntp_tcp_port = (unsigned short) atoi(optarg);
  628 #else
  629                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  630                 free_all_arrays();
  631                 giveup();
  632                 /* keep lint quiet: */
  633                 /* NOTREACHED */
  634 #endif /* NNTP_ABLE */
  635                 break;
  636 
  637             case 'q':
  638                 check_for_new_newsgroups = FALSE;
  639                 break;
  640 
  641             case 'Q':
  642                 newsrc_active = TRUE;
  643                 check_for_new_newsgroups = FALSE;
  644                 show_description = FALSE;
  645                 break;
  646 
  647             case 'r':   /* read news remotely from default NNTP server */
  648 #ifdef NNTP_ABLE
  649                 read_news_via_nntp = TRUE;
  650 #else
  651                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  652                 free_all_arrays();
  653                 giveup();
  654                 /* keep lint quiet: */
  655                 /* NOTREACHED */
  656 #endif /* NNTP_ABLE */
  657                 break;
  658 
  659             case 'R':   /* read news saved by -S option */
  660                 read_saved_news = TRUE;
  661                 list_active = TRUE;
  662                 newsrc_active = FALSE;
  663                 check_for_new_newsgroups = FALSE;
  664                 my_strncpy(news_active_file, save_active_file, sizeof(news_active_file) - 1);
  665                 break;
  666 
  667             case 's':
  668                 my_strncpy(cmdline.savedir, optarg, sizeof(cmdline.savedir) - 1);
  669                 cmdline.args |= CMDLINE_SAVEDIR;
  670                 break;
  671 
  672             case 'S':   /* save new news to dir structure */
  673                 save_news = TRUE;
  674                 batch_mode = TRUE;
  675                 break;
  676 
  677             case 'u':   /* update index files */
  678                 batch_mode = TRUE;
  679                 update_index = TRUE;
  680                 break;
  681 
  682             case 'v':   /* verbose mode, can be used multiple times */
  683                 verbose++;
  684                 break;
  685 
  686             case 'V':
  687                 tin_version_info(stderr);
  688                 free_all_arrays();
  689                 exit(EXIT_SUCCESS);
  690                 /* keep lint quiet: */
  691                 /* FALLTHROUGH */
  692 
  693             case 'w':   /* post article & exit */
  694 #ifndef NO_POSTING
  695                 post_article_and_exit = TRUE;
  696                 check_for_new_newsgroups = FALSE;
  697 #else
  698                 error_message(2, _(txt_option_not_enabled), "-UNO_POSTING");
  699                 free_all_arrays();
  700                 giveup();
  701                 /* keep lint quiet: */
  702                 /* NOTREACHED */
  703 #endif /* !NO_POSTING */
  704                 break;
  705 
  706 #if 0
  707             case 'W':   /* reserved according to SUSV3 XDB Utility Syntax Guidelines, Guideline 3 */
  708                 break;
  709 #endif /* 0 */
  710 
  711             case 'x':   /* enter no_posting mode */
  712                 force_no_post = TRUE;
  713                 break;
  714 
  715             case 'X':   /* don't save ~/.newsrc on exit */
  716                 no_write = TRUE;
  717                 break;
  718 
  719             case 'z':
  720                 start_any_unread = TRUE;
  721                 break;
  722 
  723             case 'Z':
  724                 check_any_unread = TRUE;
  725                 batch_mode = TRUE;
  726                 break;
  727 
  728             case 'h':
  729             case '?':
  730             default:
  731                 usage(tin_progname);
  732                 free_all_arrays();
  733                 exit(EXIT_SUCCESS);
  734         }
  735     }
  736     cmdargs = argv;
  737     num_cmdargs = optind;
  738     max_cmdargs = argc;
  739     if (!newsrc_set) {
  740         if (read_news_via_nntp) {
  741             nntp_server = getserverbyfile(NNTP_SERVER_FILE);
  742             get_newsrcname(newsrc, sizeof(newsrc), nntp_server);
  743         } else {
  744 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
  745             struct utsname uts;
  746             (void) uname(&uts);
  747             get_newsrcname(newsrc, sizeof(newsrc), uts.nodename);
  748 #else
  749             char nodenamebuf[256]; /* SUSv2 limit; better use HOST_NAME_MAX */
  750 #   ifdef HAVE_GETHOSTNAME
  751             (void) gethostname(nodenamebuf, sizeof(nodenamebuf));
  752 #   endif /* HAVE_GETHOSTNAME */
  753             get_newsrcname(newsrc, sizeof(newsrc), nodenamebuf);
  754 #endif /* HAVE_SYS_UTSNAME_H && HAVE_UNAME */
  755         }
  756     }
  757 
  758     /*
  759      * Sort out option conflicts
  760      */
  761     if (!batch_mode) {
  762         if (catchup) {
  763             wait_message(2, _(txt_useful_with_batch_mode), "-c");
  764             catchup = FALSE;
  765         }
  766     } else {
  767         if (read_saved_news) {
  768             wait_message(2, _(txt_useful_without_batch_mode), "-R");
  769             read_saved_news = FALSE;
  770         }
  771     }
  772     if (!(batch_mode || debug)) {
  773         if (verbose) {
  774             wait_message(2, _(txt_useful_with_batch_or_debug_mode), "-v");
  775             verbose = FALSE;
  776         }
  777     }
  778     if (post_postponed_and_exit && force_no_post) {
  779         wait_message(2, _(txt_useless_combination), "-o", "-x", "-x");
  780         force_no_post = FALSE;
  781     }
  782     if (post_article_and_exit && force_no_post) {
  783         wait_message(2, _(txt_useless_combination), "-w", "-x", "-x");
  784         force_no_post = FALSE;
  785     }
  786     if (catchup && start_any_unread) {
  787         wait_message(2, _(txt_useless_combination), "-c", "-z", "-c");
  788         catchup = FALSE;
  789     }
  790     if (catchup && no_write) {
  791         wait_message(2, _(txt_useless_combination), "-c", "-X", "-c");
  792         catchup = FALSE;
  793     }
  794     if (catchup && check_any_unread) {
  795         wait_message(2, _(txt_useless_combination), "-c", "-Z", "-c");
  796         catchup = FALSE;
  797     }
  798     if (newsrc_active && read_saved_news) {
  799         wait_message(2, _(txt_useless_combination), "-n", "-R", "-n");
  800         newsrc_active = read_news_via_nntp = FALSE;
  801     }
  802     if (start_any_unread && save_news) {
  803         wait_message(2, _(txt_useless_combination), "-z", "-S", "-z");
  804         start_any_unread = FALSE;
  805     }
  806     if (save_news && check_any_unread) {
  807         wait_message(2, _(txt_useless_combination), "-S", "-Z", "-S");
  808         save_news = FALSE;
  809     }
  810     if (start_any_unread && check_any_unread) {
  811         wait_message(2, _(txt_useless_combination), "-Z", "-z", "-Z");
  812         check_any_unread = FALSE;
  813     }
  814 #   ifdef DEBUG
  815     if ((debug & DEBUG_NNTP) && !read_news_via_nntp) {
  816         /* TODO: lang.c */
  817         wait_message(3, _(txt_useless_combination), _("reading from local spool"), "-D nntp", "-D nntp");
  818         debug &= ~DEBUG_NNTP;
  819     }
  820 #   endif /* DEBUG */
  821 
  822 #if defined(NNTP_ABLE) && defined(INET6)
  823     if (force_ipv4 && force_ipv6) {
  824         wait_message(2, _(txt_useless_combination), "-4", "-6", "-6");
  825         force_ipv6 = FALSE;
  826     }
  827 #endif /* NNTP_ABLE && INET6 */
  828 
  829     if (mail_news || save_news || update_index || check_any_unread || catchup)
  830         batch_mode = TRUE;
  831     else
  832         batch_mode = FALSE;
  833     if (batch_mode && (post_article_and_exit || post_postponed_and_exit))
  834         batch_mode = FALSE;
  835 
  836     /*
  837      * When updating index files set getart_limit to 0 in order to get overview
  838      * information for all article; this overwrites '-G limit' and disables
  839      * tinrc.getart_limit temporary
  840      */
  841     if (update_index) {
  842         cmdline.getart_limit = 0;
  843         cmdline.args |= CMDLINE_GETART_LIMIT;
  844     }
  845 #ifdef NNTP_ABLE
  846     /*
  847      * If we're reading from an NNTP server and we've been asked not to look
  848      * for new newsgroups, trust our cached copy of the newsgroups file.
  849      */
  850     if (read_news_via_nntp)
  851         read_local_newsgroups_file = bool_not(check_for_new_newsgroups);
  852 #endif /* NNTP_ABLE */
  853     /*
  854      * If we use neither list_active nor newsrc_active,
  855      * we use both of them.
  856      */
  857     if (!list_active && !newsrc_active)
  858         list_active = newsrc_active = TRUE;
  859 }
  860 
  861 
  862 /*
  863  * usage
  864  */
  865 static void
  866 usage(
  867     char *theProgname)
  868 {
  869     error_message(2, _(txt_usage_tin), theProgname);
  870 
  871 #if defined(NNTP_ABLE) && defined(INET6)
  872     error_message(2, _(txt_usage_force_ipv4));
  873     error_message(2, _(txt_usage_force_ipv6));
  874 #endif /* NNTP_ABLE && INET6 */
  875 
  876 #ifdef HAVE_COLOR
  877     error_message(2, _(txt_usage_toggle_color));
  878 #endif /* HAVE_COLOR */
  879 #ifdef NNTP_ABLE
  880     error_message(2, _(txt_usage_force_authentication));
  881 #endif /* NNTP_ABLE */
  882 
  883     error_message(2, _(txt_usage_catchup));
  884     error_message(2, _(txt_usage_dont_show_descriptions));
  885 
  886 #ifdef DEBUG
  887     error_message(2, _(txt_usage_debug));
  888 #endif /* DEBUG */
  889 
  890     error_message(2, _(txt_usage_newsrc_file), newsrc);
  891     error_message(2, _(txt_usage_getart_limit));
  892 
  893 #ifdef NNTP_ABLE
  894 #   ifdef NNTP_DEFAULT_SERVER
  895     error_message(2, _(txt_usage_newsserver), get_val("NNTPSERVER", NNTP_DEFAULT_SERVER));
  896 #   else
  897     error_message(2, _(txt_usage_newsserver), get_val("NNTPSERVER", "news"));
  898 #   endif /* NNTP_DEFAULT_SERVER */
  899 #endif /* NNTP_ABLE */
  900 
  901     error_message(2, _(txt_usage_help_message));
  902     error_message(2, _(txt_usage_help_information), theProgname);
  903     error_message(2, _(txt_usage_index_newsdir), index_newsdir);
  904     error_message(2, _(txt_usage_read_only_active));
  905     error_message(2, _(txt_usage_maildir), tinrc.maildir);
  906     error_message(2, _(txt_usage_mail_new_news_to_user));
  907     error_message(2, _(txt_usage_read_only_subscribed));
  908     error_message(2, _(txt_usage_mail_new_news));
  909     error_message(2, _(txt_usage_post_postponed_arts));
  910 
  911 #ifdef NNTP_ABLE
  912     error_message(2, _(txt_usage_port), nntp_tcp_port);
  913 #endif /* NNTP_ABLE */
  914 
  915     error_message(2, _(txt_usage_dont_check_new_newsgroups));
  916     error_message(2, _(txt_usage_quickstart));
  917 
  918 #ifdef NNTP_ABLE
  919     if (!read_news_via_nntp)
  920         error_message(2, _(txt_usage_read_news_remotely));
  921 #endif /* NNTP_ABLE */
  922 
  923     error_message(2, _(txt_usage_read_saved_news));
  924     error_message(2, _(txt_usage_savedir), tinrc.savedir);
  925     error_message(2, _(txt_usage_save_new_news));
  926     error_message(2, _(txt_usage_update_index_files));
  927     error_message(2, _(txt_usage_verbose));
  928     error_message(2, _(txt_usage_version));
  929     error_message(2, _(txt_usage_post_article));
  930     error_message(2, _(txt_usage_no_posting));
  931     error_message(2, _(txt_usage_dont_save_files_on_quit));
  932     error_message(2, _(txt_usage_start_if_unread_news));
  933     error_message(2, _(txt_usage_check_for_unread_news));
  934 
  935     error_message(2, _(txt_usage_mail_bugreport), bug_addr);
  936 }
  937 
  938 
  939 /*
  940  * update index files
  941  */
  942 static void
  943 update_index_files(
  944     void)
  945 {
  946     cCOLS = 132;                            /* set because curses has not started */
  947     create_index_lock_file(lock_file);
  948     tinrc.thread_articles = THREAD_NONE;    /* stop threading to run faster */
  949     do_update(catchup);
  950     tin_done(EXIT_SUCCESS, NULL);
  951 }
  952 
  953 
  954 /*
  955  * display page of general info. for first time user.
  956  */
  957 static void
  958 show_intro_page(
  959     void)
  960 {
  961     char buf[4096];
  962 
  963     if (!cmd_line) {
  964         ClearScreen();
  965         center_line(0, TRUE, cvers);
  966         Raw(FALSE);
  967         my_printf("\n");
  968     }
  969 
  970     snprintf(buf, sizeof(buf), _(txt_intro_page), PRODUCT, PRODUCT, PRODUCT, bug_addr);
  971 
  972     my_fputs(buf, stdout);
  973     my_flush();
  974 
  975     if (!cmd_line) {
  976         Raw(TRUE);
  977         prompt_continue();
  978     }
  979 }
  980 
  981 
  982 /*
  983  * Wildcard match any newsgroups on the command line. Sort of like a limited
  984  * yank at startup. Return number of groups that were matched.
  985  */
  986 int
  987 read_cmd_line_groups(
  988     void)
  989 {
  990     int matched = 0;
  991     int num;
  992     int i;
  993 
  994     if (num_cmdargs < max_cmdargs) {
  995         selmenu.max = skip_newgroups();     /* Reposition after any newgroups */
  996 
  997         for (num = num_cmdargs; num < max_cmdargs; num++) {
  998             if (!batch_mode)
  999                 wait_message(0, _(txt_matching_cmd_line_groups), cmdargs[num]);
 1000 
 1001             for_each_group(i) {
 1002                 if (match_group_list(active[i].name, cmdargs[num])) {
 1003                     if (my_group_add(active[i].name, TRUE) != -1) {
 1004                         matched++;
 1005                         if (post_article_and_exit) {
 1006                             my_strncpy(tinrc.default_post_newsgroups, active[i].name, sizeof(tinrc.default_post_newsgroups) - 1);
 1007                             break;
 1008                         }
 1009                     }
 1010                 }
 1011             }
 1012         }
 1013     }
 1014     return matched;
 1015 }
 1016 
 1017 
 1018 /*
 1019  * Create default mail & save directories if they do not exist
 1020  */
 1021 static void
 1022 create_mail_save_dirs(
 1023     void)
 1024 {
 1025     char path[PATH_LEN];
 1026     struct stat sb;
 1027 
 1028     if (!strfpath(tinrc.maildir, path, sizeof(path), NULL, FALSE))
 1029         joinpath(path, sizeof(path), homedir, DEFAULT_MAILDIR);
 1030 
 1031     if (stat(path, &sb) == -1)
 1032         my_mkdir(path, (mode_t) (S_IRWXU));
 1033 
 1034     if (!strfpath(tinrc.savedir, path, sizeof(path), NULL, FALSE))
 1035         joinpath(path, sizeof(path), homedir, DEFAULT_SAVEDIR);
 1036 
 1037     if (stat(path, &sb) == -1)
 1038         my_mkdir(path, (mode_t) (S_IRWXU));
 1039 }
 1040 
 1041 
 1042 /*
 1043  * we don't try do free() any previously malloc()ed mem here as exit via
 1044  * giveup() indicates a serious error and keeping track of what we've
 1045  * already malloc()ed would be a PITA.
 1046  */
 1047 /* coverity[+kill] */
 1048 void
 1049 giveup(
 1050     void)
 1051 {
 1052     static int nested;
 1053 
 1054 #ifdef XFACE_ABLE
 1055     slrnface_stop();
 1056 #endif /* XFACE_ABLE */
 1057 
 1058     if (!cmd_line && !nested++) {
 1059         cursoron();
 1060         EndWin();
 1061         Raw(FALSE);
 1062     }
 1063     exit(EXIT_FAILURE);
 1064 }