"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.6.1/src/main.c" (22 Dec 2021, 27316 Bytes) of package /linux/misc/tin-2.6.1.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.6.0_vs_2.6.1.

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