"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.3/src/main.c" (23 Nov 2018, 26720 Bytes) of package /linux/misc/tin-2.4.3.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.2_vs_2.4.3.

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