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
main(int argc,char * argv[])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
read_cmd_line_options(int argc,char * argv[])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
usage(char * theProgname)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
update_index_files(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
show_intro_page(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
read_cmd_line_groups(void)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
create_mail_save_dirs(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
giveup(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 }
1069