"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.5/src/main.c" (1 Dec 2020, 27115 Bytes) of package /linux/misc/tin-2.4.5.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.4_vs_2.4.5.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : main.c
    4  *  Author    : I. Lea & R. Skrenta
    5  *  Created   : 1991-04-01
    6  *  Updated   : 2020-05-22
    7  *  Notes     :
    8  *
    9  * Copyright (c) 1991-2021 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     if (debug & DEBUG_MISC)
  293         debug_print_active();
  294 #endif /* DEBUG */
  295 
  296     /*
  297      * Read in users filter preferences file. This has to be done before
  298      * quick post because the filters might be updated.
  299      */
  300     read_filter_file(filter_file);
  301 
  302     no_write = TRUE;
  303 #ifdef DEBUG
  304     if (debug & DEBUG_FILTER)
  305         debug_print_filters();
  306 #endif /* DEBUG */
  307 
  308     /*
  309      * Preloads active[] with command line groups. They will follow any
  310      * new newsgroups
  311      */
  312     if (!post_postponed_and_exit)
  313         num_cmd_line_groups = read_cmd_line_groups();
  314 
  315     /*
  316      * Quick post an article and exit if -w or -o specified
  317      */
  318     if (post_article_and_exit || post_postponed_and_exit) {
  319         no_write = tmp_no_write; /* restore original value */
  320         quick_post_article(post_postponed_and_exit, num_cmd_line_groups);
  321         wait_message(2, _(txt_exiting));
  322         no_write = TRUE; /* disable newsrc updates */
  323         tin_done(EXIT_SUCCESS, NULL);
  324     }
  325 
  326     /* TODO: replace hard coded key-name in txt_info_postponed */
  327     if ((count = count_postponed_articles()))
  328         wait_message(3, _(txt_info_postponed), count, PLURAL(count, txt_article));
  329 
  330     /*
  331      * Read text descriptions for mail and/or news groups
  332      */
  333     if (show_description && !batch_mode) {
  334         no_write = tmp_no_write; /* restore original value */
  335         read_descriptions(TRUE);
  336         no_write = TRUE; /* disable newsrc updates */
  337     }
  338 
  339     /* what about "if (!no_write)" here? */
  340     create_mail_save_dirs();
  341     if (created_rcdir) /* first start */
  342         write_config_file(local_config_file);
  343 
  344     if (!tmp_no_write)  /* do not (over)write oldnewsrc with -X */
  345         backup_newsrc();
  346 
  347     /*
  348      * Load my_groups[] from the .newsrc file. We append these groups to any
  349      * new newsgroups and command line newsgroups already loaded. Also does
  350      * auto-subscribe to groups specified in /usr/lib/news/subscriptions
  351      * locally or via NNTP if reading news remotely (LIST SUBSCRIPTIONS)
  352      */
  353     /*
  354      * TODO:
  355      * if (num_cmd_line_groups != 0 && check_any_unread)
  356      * don't read newsrc.
  357      * This makes -Z handle command line newsgroups. Test & document
  358      */
  359     read_newsrc_lines = read_newsrc(newsrc, FALSE);
  360     no_write = tmp_no_write; /* restore old value */
  361 
  362     /*
  363      * We have to show all groups with command line groups
  364      */
  365     if (num_cmd_line_groups)
  366         tinrc.show_only_unread_groups = FALSE;
  367     else
  368         toggle_my_groups(NULL);
  369 
  370     /*
  371      * Check/start if any new/unread articles
  372      */
  373     if (check_any_unread)
  374         tin_done(check_start_save_any_news(CHECK_ANY_NEWS, catchup), NULL);
  375 
  376     if (start_any_unread) {
  377         batch_mode = TRUE;          /* Suppress some unwanted on-screen garbage */
  378         if ((start_groupnum = check_start_save_any_news(START_ANY_NEWS, catchup)) == -1) {
  379             batch_mode = FALSE;
  380             tin_done(EXIT_SUCCESS, NULL);
  381         }
  382         batch_mode = FALSE;
  383     }
  384 
  385     /*
  386      * Mail any new articles to specified user
  387      * or
  388      * Save any new articles to savedir structure for later reading
  389      *
  390      * TODO: should we temporarily set
  391      *       getart_limit=-1,thread_articles=0,sort_article_type=0
  392      *       for speed reasons?
  393      */
  394     if (mail_news || save_news) {
  395         check_start_save_any_news(mail_news ? MAIL_ANY_NEWS : SAVE_ANY_NEWS, catchup);
  396         tin_done(EXIT_SUCCESS, NULL);
  397     }
  398 
  399     /*
  400      * Catchup newsrc file (-c option)
  401      */
  402     if (batch_mode && catchup && !update_index) {
  403         catchup_newsrc_file();
  404         tin_done(EXIT_SUCCESS, NULL);
  405     }
  406 
  407     /*
  408      * Update index files (-u option), also does catchup if requested
  409      */
  410     if (update_index)
  411         update_index_files();
  412 
  413     /*
  414      * the code below this point can't be reached in batch mode
  415      */
  416 
  417     /*
  418      * If first time print welcome screen
  419      */
  420     if (created_rcdir)
  421         show_intro_page();
  422 
  423 #ifdef XFACE_ABLE
  424     if (tinrc.use_slrnface && !batch_mode)
  425         slrnface_start();
  426 #endif /* XFACE_ABLE */
  427 
  428 #ifdef USE_CURSES
  429     /* Turn scrolling off now the startup messages have been displayed */
  430     scrollok(stdscr, FALSE);
  431 #endif /* USE_CURSES */
  432 
  433     /*
  434      * Work loop
  435      */
  436     selection_page(start_groupnum, num_cmd_line_groups);
  437     /* NOTREACHED */
  438     return 0;
  439 }
  440 
  441 
  442 /*
  443  * process command line options
  444  * [01235789beEFijJkKLOtTyY] are unused
  445  * [W] is reserved
  446  * [BCPU] have been in use at some time, but now are unused:
  447  *   B BBS mode (M_AMIGA only)
  448  *   C count articles
  449  *   P purge group index files of articles that no longer exist
  450  *   U update index files in background
  451  */
  452 #define OPTIONS "46aAcdD:f:g:G:hHI:lm:M:nNop:qQrRs:SuvVwxXzZ"
  453 
  454 static void
  455 read_cmd_line_options(
  456     int argc,
  457     char *argv[])
  458 {
  459     int ch;
  460     t_bool newsrc_set = FALSE;
  461 
  462     envargs(&argc, &argv, "TINRC");
  463 
  464     while ((ch = getopt(argc, argv, OPTIONS)) != -1) {
  465         switch (ch) {
  466 
  467             case '4':
  468 #if defined(NNTP_ABLE) && defined(INET6)
  469                 force_ipv4 = TRUE;
  470                 read_news_via_nntp = TRUE;
  471 #else
  472 #   ifdef NNTP_ABLE
  473                 error_message(2, _(txt_option_not_enabled), "-DENABLE_IPV6");
  474 #   else
  475                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  476 #   endif /* NNTP_ABLE */
  477                 free_all_arrays();
  478                 giveup();
  479                 /* keep lint quiet: */
  480                 /* NOTREACHED */
  481 #endif /* NNTP_ABLE && INET6 */
  482                 break;
  483 
  484             case '6':
  485 #if defined(NNTP_ABLE) && defined(INET6)
  486                 force_ipv6 = TRUE;
  487                 read_news_via_nntp = TRUE;
  488 #   else
  489 #   ifdef NNTP_ABLE
  490                 error_message(2, _(txt_option_not_enabled), "-DENABLE_IPV6");
  491 #   else
  492                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  493 #   endif /* NNTP_ABLE */
  494                 free_all_arrays();
  495                 giveup();
  496                 /* keep lint quiet: */
  497                 /* NOTREACHED */
  498 #endif /* NNTP_ABLE && INET6 */
  499                 break;
  500 
  501             case 'a':
  502 #ifdef HAVE_COLOR
  503                 cmdline.args |= CMDLINE_USE_COLOR;
  504 #else
  505                 error_message(2, _(txt_option_not_enabled), "-DHAVE_COLOR");
  506                 free_all_arrays();
  507                 giveup();
  508                 /* keep lint quiet: */
  509                 /* NOTREACHED */
  510 #endif /* HAVE_COLOR */
  511                 break;
  512 
  513             case 'A':
  514 #ifdef NNTP_ABLE
  515                 force_auth_on_conn_open = TRUE;
  516                 read_news_via_nntp = TRUE;
  517 #else
  518                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  519                 free_all_arrays();
  520                 giveup();
  521                 /* keep lint quiet: */
  522                 /* NOTREACHED */
  523 #endif /* NNTP_ABLE */
  524                 break;
  525 
  526             case 'c':
  527                 batch_mode = TRUE;
  528                 catchup = TRUE;
  529                 break;
  530 
  531             case 'd':
  532                 show_description = FALSE;
  533                 break;
  534 
  535             case 'D':       /* debug mode */
  536 #ifdef DEBUG
  537                 debug = atoi(optarg) & 0xff;
  538                 debug_delete_files();
  539 #else
  540                 error_message(2, _(txt_option_not_enabled), "-DDEBUG");
  541                 free_all_arrays();
  542                 giveup();
  543                 /* keep lint quiet: */
  544                 /* NOTREACHED */
  545 #endif /* DEBUG */
  546                 break;
  547 
  548             case 'f':   /* newsrc file */
  549                 my_strncpy(newsrc, optarg, sizeof(newsrc) - 1);
  550                 newsrc_set = TRUE;
  551                 break;
  552 
  553             case 'G':
  554                 cmdline.getart_limit = atoi(optarg);
  555                 cmdline.args |= CMDLINE_GETART_LIMIT;
  556                 break;
  557 
  558             case 'g':   /* select alternative NNTP-server, implies -r */
  559 #ifdef NNTP_ABLE
  560                 my_strncpy(cmdline.nntpserver, optarg, sizeof(cmdline.nntpserver) - 1);
  561                 cmdline.args |= CMDLINE_NNTPSERVER;
  562                 read_news_via_nntp = TRUE;
  563 #else
  564                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  565                 free_all_arrays();
  566                 giveup();
  567                 /* keep lint quiet: */
  568                 /* NOTREACHED */
  569 #endif /* NNTP_ABLE */
  570                 break;
  571 
  572             case 'H':
  573                 show_intro_page();
  574                 free_all_arrays();
  575                 exit(EXIT_SUCCESS);
  576                 /* keep lint quiet: */
  577                 /* FALLTHROUGH */
  578 
  579             case 'I':
  580                 joinpath(index_newsdir, sizeof(index_newsdir), optarg, INDEX_NEWSDIR);
  581                 break;
  582 
  583             case 'l':
  584                 list_active = TRUE;
  585                 break;
  586 
  587             case 'm':
  588                 my_strncpy(cmdline.maildir, optarg, sizeof(cmdline.maildir) - 1);
  589                 cmdline.args |= CMDLINE_MAILDIR;
  590                 break;
  591 
  592             case 'M':   /* mail new news to specified user */
  593                 my_strncpy(mail_news_user, optarg, sizeof(mail_news_user) - 1);
  594                 mail_news = TRUE;
  595                 batch_mode = TRUE;
  596                 break;
  597 
  598             case 'n':
  599                 newsrc_active = TRUE;
  600                 break;
  601 
  602             case 'N':   /* mail new news to your posts */
  603                 my_strncpy(mail_news_user, userid, sizeof(mail_news_user) - 1);
  604                 mail_news = TRUE;
  605                 batch_mode = TRUE;
  606                 break;
  607 
  608             case 'o':   /* post postponed articles & exit */
  609 #ifndef NO_POSTING
  610                 /*
  611                  * TODO: autoposting currently does some screen output, so we
  612                  *       can't set batch_mode
  613                  */
  614                 post_postponed_and_exit = TRUE;
  615                 check_for_new_newsgroups = FALSE;
  616 #else
  617                 error_message(2, _(txt_option_not_enabled), "-UNO_POSTING");
  618                 free_all_arrays();
  619                 giveup();
  620                 /* keep lint quiet: */
  621                 /* NOTREACHED */
  622 #endif /* !NO_POSTING */
  623                 break;
  624 
  625             case 'p': /* implies -r */
  626 #ifdef NNTP_ABLE
  627                 read_news_via_nntp = TRUE;
  628                 if (atoi(optarg) != 0)
  629                     nntp_tcp_port = (unsigned short) atoi(optarg);
  630 #else
  631                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  632                 free_all_arrays();
  633                 giveup();
  634                 /* keep lint quiet: */
  635                 /* NOTREACHED */
  636 #endif /* NNTP_ABLE */
  637                 break;
  638 
  639             case 'q':
  640                 check_for_new_newsgroups = FALSE;
  641                 break;
  642 
  643             case 'Q':
  644                 newsrc_active = TRUE;
  645                 check_for_new_newsgroups = FALSE;
  646                 show_description = FALSE;
  647                 break;
  648 
  649             case 'r':   /* read news remotely from default NNTP server */
  650 #ifdef NNTP_ABLE
  651                 read_news_via_nntp = TRUE;
  652 #else
  653                 error_message(2, _(txt_option_not_enabled), "-DNNTP_ABLE");
  654                 free_all_arrays();
  655                 giveup();
  656                 /* keep lint quiet: */
  657                 /* NOTREACHED */
  658 #endif /* NNTP_ABLE */
  659                 break;
  660 
  661             case 'R':   /* read news saved by -S option */
  662                 read_saved_news = TRUE;
  663                 list_active = TRUE;
  664                 newsrc_active = FALSE;
  665                 check_for_new_newsgroups = FALSE;
  666                 my_strncpy(news_active_file, save_active_file, sizeof(news_active_file) - 1);
  667                 break;
  668 
  669             case 's':
  670                 my_strncpy(cmdline.savedir, optarg, sizeof(cmdline.savedir) - 1);
  671                 cmdline.args |= CMDLINE_SAVEDIR;
  672                 break;
  673 
  674             case 'S':   /* save new news to dir structure */
  675                 save_news = TRUE;
  676                 batch_mode = TRUE;
  677                 break;
  678 
  679             case 'u':   /* update index files */
  680                 batch_mode = TRUE;
  681                 update_index = TRUE;
  682                 break;
  683 
  684             case 'v':   /* verbose mode, can be used multiple times */
  685                 verbose++;
  686                 break;
  687 
  688             case 'V':
  689                 tin_version_info(stderr);
  690                 free_all_arrays();
  691                 exit(EXIT_SUCCESS);
  692                 /* keep lint quiet: */
  693                 /* FALLTHROUGH */
  694 
  695             case 'w':   /* post article & exit */
  696 #ifndef NO_POSTING
  697                 post_article_and_exit = TRUE;
  698                 check_for_new_newsgroups = FALSE;
  699 #else
  700                 error_message(2, _(txt_option_not_enabled), "-UNO_POSTING");
  701                 free_all_arrays();
  702                 giveup();
  703                 /* keep lint quiet: */
  704                 /* NOTREACHED */
  705 #endif /* !NO_POSTING */
  706                 break;
  707 
  708 #if 0
  709             case 'W':   /* reserved according to SUSV3 XDB Utility Syntax Guidelines, Guideline 3 */
  710                 break;
  711 #endif /* 0 */
  712 
  713             case 'x':   /* enter no_posting mode */
  714                 force_no_post = TRUE;
  715                 break;
  716 
  717             case 'X':   /* don't save ~/.newsrc on exit */
  718                 no_write = TRUE;
  719                 break;
  720 
  721             case 'z':
  722                 start_any_unread = TRUE;
  723                 break;
  724 
  725             case 'Z':
  726                 check_any_unread = TRUE;
  727                 batch_mode = TRUE;
  728                 break;
  729 
  730             case 'h':
  731             case '?':
  732             default:
  733                 usage(tin_progname);
  734                 free_all_arrays();
  735                 exit(EXIT_SUCCESS);
  736         }
  737     }
  738     cmdargs = argv;
  739     num_cmdargs = optind;
  740     max_cmdargs = argc;
  741     if (!newsrc_set) {
  742         if (read_news_via_nntp) {
  743             nntp_server = getserverbyfile(NNTP_SERVER_FILE);
  744             get_newsrcname(newsrc, sizeof(newsrc), nntp_server);
  745         } else {
  746 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
  747             struct utsname uts;
  748             (void) uname(&uts);
  749             get_newsrcname(newsrc, sizeof(newsrc), uts.nodename);
  750 #else
  751             char nodenamebuf[256]; /* SUSv2 limit; better use HOST_NAME_MAX */
  752 #   ifdef HAVE_GETHOSTNAME
  753             (void) gethostname(nodenamebuf, sizeof(nodenamebuf));
  754 #   endif /* HAVE_GETHOSTNAME */
  755             get_newsrcname(newsrc, sizeof(newsrc), nodenamebuf);
  756 #endif /* HAVE_SYS_UTSNAME_H && HAVE_UNAME */
  757         }
  758     }
  759 
  760     /*
  761      * Sort out option conflicts
  762      */
  763     if (!batch_mode) {
  764         if (catchup) {
  765             wait_message(2, _(txt_useful_with_batch_mode), "-c");
  766             catchup = FALSE;
  767         }
  768     } else {
  769         if (read_saved_news) {
  770             wait_message(2, _(txt_useful_without_batch_mode), "-R");
  771             read_saved_news = FALSE;
  772         }
  773     }
  774     if (!(batch_mode || debug)) {
  775         if (verbose) {
  776             wait_message(2, _(txt_useful_with_batch_or_debug_mode), "-v");
  777             verbose = FALSE;
  778         }
  779     }
  780     if (post_postponed_and_exit && force_no_post) {
  781         wait_message(2, _(txt_useless_combination), "-o", "-x", "-x");
  782         force_no_post = FALSE;
  783     }
  784     if (post_article_and_exit && force_no_post) {
  785         wait_message(2, _(txt_useless_combination), "-w", "-x", "-x");
  786         force_no_post = FALSE;
  787     }
  788     if (catchup && start_any_unread) {
  789         wait_message(2, _(txt_useless_combination), "-c", "-z", "-c");
  790         catchup = FALSE;
  791     }
  792     if (catchup && no_write) {
  793         wait_message(2, _(txt_useless_combination), "-c", "-X", "-c");
  794         catchup = FALSE;
  795     }
  796     if (catchup && check_any_unread) {
  797         wait_message(2, _(txt_useless_combination), "-c", "-Z", "-c");
  798         catchup = FALSE;
  799     }
  800     if (newsrc_active && read_saved_news) {
  801         wait_message(2, _(txt_useless_combination), "-n", "-R", "-n");
  802         newsrc_active = read_news_via_nntp = FALSE;
  803     }
  804     if (start_any_unread && save_news) {
  805         wait_message(2, _(txt_useless_combination), "-z", "-S", "-z");
  806         start_any_unread = FALSE;
  807     }
  808     if (save_news && check_any_unread) {
  809         wait_message(2, _(txt_useless_combination), "-S", "-Z", "-S");
  810         save_news = FALSE;
  811     }
  812     if (start_any_unread && check_any_unread) {
  813         wait_message(2, _(txt_useless_combination), "-Z", "-z", "-Z");
  814         check_any_unread = FALSE;
  815     }
  816 #   ifdef DEBUG
  817     if ((debug & DEBUG_NNTP) && !read_news_via_nntp) {
  818         /* TODO: lang.c */
  819         wait_message(3, _(txt_useless_combination), _("reading from local spool"), "-D nntp", "-D nntp");
  820         debug &= ~DEBUG_NNTP;
  821     }
  822 #   endif /* DEBUG */
  823 
  824 #if defined(NNTP_ABLE) && defined(INET6)
  825     if (force_ipv4 && force_ipv6) {
  826         wait_message(2, _(txt_useless_combination), "-4", "-6", "-6");
  827         force_ipv6 = FALSE;
  828     }
  829 #endif /* NNTP_ABLE && INET6 */
  830 
  831     if (mail_news || save_news || update_index || check_any_unread || catchup)
  832         batch_mode = TRUE;
  833     else
  834         batch_mode = FALSE;
  835     if (batch_mode && (post_article_and_exit || post_postponed_and_exit))
  836         batch_mode = FALSE;
  837 
  838     /*
  839      * When updating index files set getart_limit to 0 in order to get overview
  840      * information for all article; this overwrites '-G limit' and disables
  841      * tinrc.getart_limit temporary
  842      */
  843     if (update_index) {
  844         cmdline.getart_limit = 0;
  845         cmdline.args |= CMDLINE_GETART_LIMIT;
  846     }
  847 #ifdef NNTP_ABLE
  848     /*
  849      * If we're reading from an NNTP server and we've been asked not to look
  850      * for new newsgroups, trust our cached copy of the newsgroups file.
  851      */
  852     if (read_news_via_nntp)
  853         read_local_newsgroups_file = bool_not(check_for_new_newsgroups);
  854 #endif /* NNTP_ABLE */
  855     /*
  856      * If we use neither list_active nor newsrc_active,
  857      * we use both of them.
  858      */
  859     if (!list_active && !newsrc_active)
  860         list_active = newsrc_active = TRUE;
  861 }
  862 
  863 
  864 /*
  865  * usage
  866  */
  867 static void
  868 usage(
  869     char *theProgname)
  870 {
  871     error_message(2, _(txt_usage_tin), theProgname);
  872 
  873 #if defined(NNTP_ABLE) && defined(INET6)
  874     error_message(2, _(txt_usage_force_ipv4));
  875     error_message(2, _(txt_usage_force_ipv6));
  876 #endif /* NNTP_ABLE && INET6 */
  877 
  878 #ifdef HAVE_COLOR
  879     error_message(2, _(txt_usage_toggle_color));
  880 #endif /* HAVE_COLOR */
  881 #ifdef NNTP_ABLE
  882     error_message(2, _(txt_usage_force_authentication));
  883 #endif /* NNTP_ABLE */
  884 
  885     error_message(2, _(txt_usage_catchup));
  886     error_message(2, _(txt_usage_dont_show_descriptions));
  887 
  888 #ifdef DEBUG
  889     error_message(2, _(txt_usage_debug));
  890 #endif /* DEBUG */
  891 
  892     error_message(2, _(txt_usage_newsrc_file), newsrc);
  893     error_message(2, _(txt_usage_getart_limit));
  894 
  895 #ifdef NNTP_ABLE
  896 #   ifdef NNTP_DEFAULT_SERVER
  897     error_message(2, _(txt_usage_newsserver), get_val("NNTPSERVER", NNTP_DEFAULT_SERVER));
  898 #   else
  899     error_message(2, _(txt_usage_newsserver), get_val("NNTPSERVER", "news"));
  900 #   endif /* NNTP_DEFAULT_SERVER */
  901 #endif /* NNTP_ABLE */
  902 
  903     error_message(2, _(txt_usage_help_message));
  904     error_message(2, _(txt_usage_help_information), theProgname);
  905     error_message(2, _(txt_usage_index_newsdir), index_newsdir);
  906     error_message(2, _(txt_usage_read_only_active));
  907     error_message(2, _(txt_usage_maildir), tinrc.maildir);
  908     error_message(2, _(txt_usage_mail_new_news_to_user));
  909     error_message(2, _(txt_usage_read_only_subscribed));
  910     error_message(2, _(txt_usage_mail_new_news));
  911     error_message(2, _(txt_usage_post_postponed_arts));
  912 
  913 #ifdef NNTP_ABLE
  914     error_message(2, _(txt_usage_port), nntp_tcp_port);
  915 #endif /* NNTP_ABLE */
  916 
  917     error_message(2, _(txt_usage_dont_check_new_newsgroups));
  918     error_message(2, _(txt_usage_quickstart));
  919 
  920 #ifdef NNTP_ABLE
  921     if (!read_news_via_nntp)
  922         error_message(2, _(txt_usage_read_news_remotely));
  923 #endif /* NNTP_ABLE */
  924 
  925     error_message(2, _(txt_usage_read_saved_news));
  926     error_message(2, _(txt_usage_savedir), tinrc.savedir);
  927     error_message(2, _(txt_usage_save_new_news));
  928     error_message(2, _(txt_usage_update_index_files));
  929     error_message(2, _(txt_usage_verbose));
  930     error_message(2, _(txt_usage_version));
  931     error_message(2, _(txt_usage_post_article));
  932     error_message(2, _(txt_usage_no_posting));
  933     error_message(2, _(txt_usage_dont_save_files_on_quit));
  934     error_message(2, _(txt_usage_start_if_unread_news));
  935     error_message(2, _(txt_usage_check_for_unread_news));
  936 
  937     error_message(2, _(txt_usage_mail_bugreport), bug_addr);
  938 }
  939 
  940 
  941 /*
  942  * update index files
  943  */
  944 static void
  945 update_index_files(
  946     void)
  947 {
  948     cCOLS = 132;                            /* set because curses has not started */
  949     create_index_lock_file(lock_file);
  950     tinrc.thread_articles = THREAD_NONE;    /* stop threading to run faster */
  951     tinrc.sort_article_type = SORT_ARTICLES_BY_NOTHING;
  952     tinrc.sort_threads_type = SORT_THREADS_BY_NOTHING;
  953     do_update(catchup);
  954     tin_done(EXIT_SUCCESS, NULL);
  955 }
  956 
  957 
  958 /*
  959  * display page of general info. for first time user.
  960  */
  961 static void
  962 show_intro_page(
  963     void)
  964 {
  965     char buf[4096];
  966 
  967     if (!cmd_line) {
  968         ClearScreen();
  969         center_line(0, TRUE, cvers);
  970         Raw(FALSE);
  971         my_printf("\n");
  972     }
  973 
  974     snprintf(buf, sizeof(buf), _(txt_intro_page), PRODUCT, PRODUCT, PRODUCT, bug_addr);
  975 
  976     my_fputs(buf, stdout);
  977     my_flush();
  978 
  979     if (!cmd_line) {
  980         Raw(TRUE);
  981         prompt_continue();
  982     }
  983 }
  984 
  985 
  986 /*
  987  * Wildcard match any newsgroups on the command line. Sort of like a limited
  988  * yank at startup. Return number of groups that were matched.
  989  */
  990 int
  991 read_cmd_line_groups(
  992     void)
  993 {
  994     int matched = 0;
  995     int num;
  996     int i;
  997 
  998     if (num_cmdargs < max_cmdargs) {
  999         selmenu.max = skip_newgroups();     /* Reposition after any newgroups */
 1000 
 1001         for (num = num_cmdargs; num < max_cmdargs; num++) {
 1002             if (!batch_mode)
 1003                 wait_message(0, _(txt_matching_cmd_line_groups), cmdargs[num]);
 1004 
 1005             for_each_group(i) {
 1006                 if (match_group_list(active[i].name, cmdargs[num])) {
 1007                     if (my_group_add(active[i].name, TRUE) != -1) {
 1008                         matched++;
 1009                         if (post_article_and_exit) {
 1010                             my_strncpy(tinrc.default_post_newsgroups, active[i].name, sizeof(tinrc.default_post_newsgroups) - 1);
 1011                             break;
 1012                         }
 1013                     }
 1014                 }
 1015             }
 1016         }
 1017     }
 1018     return matched;
 1019 }
 1020 
 1021 
 1022 /*
 1023  * Create default mail & save directories if they do not exist
 1024  */
 1025 static void
 1026 create_mail_save_dirs(
 1027     void)
 1028 {
 1029     char path[PATH_LEN];
 1030     struct stat sb;
 1031 
 1032     if (!strfpath(tinrc.maildir, path, sizeof(path), NULL, FALSE))
 1033         joinpath(path, sizeof(path), homedir, DEFAULT_MAILDIR);
 1034 
 1035     if (stat(path, &sb) == -1)
 1036         my_mkdir(path, (mode_t) (S_IRWXU));
 1037 
 1038     if (!strfpath(tinrc.savedir, path, sizeof(path), NULL, FALSE))
 1039         joinpath(path, sizeof(path), homedir, DEFAULT_SAVEDIR);
 1040 
 1041     if (stat(path, &sb) == -1)
 1042         my_mkdir(path, (mode_t) (S_IRWXU));
 1043 }
 1044 
 1045 
 1046 /*
 1047  * we don't try do free() any previously malloc()ed mem here as exit via
 1048  * giveup() indicates a serious error and keeping track of what we've
 1049  * already malloc()ed would be a PITA.
 1050  */
 1051 /* coverity[+kill] */
 1052 void
 1053 giveup(
 1054     void)
 1055 {
 1056     static int nested;
 1057 
 1058 #ifdef XFACE_ABLE
 1059     slrnface_stop();
 1060 #endif /* XFACE_ABLE */
 1061 
 1062     if (!cmd_line && !nested++) {
 1063         cursoron();
 1064         EndWin();
 1065         Raw(FALSE);
 1066     }
 1067     exit(EXIT_FAILURE);
 1068 }