1 /*
2  *  Project   : tin - a Usenet reader
3  *  Module    : tin.h
4  *  Author    : I. Lea & R. Skrenta
5  *  Created   : 1991-04-01
6  *  Updated   : 2020-06-13
7  *  Notes     : #include files, #defines & struct's
8  *
9  * Copyright (c) 1997-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 /*
42  * OS specific doda's
43  */
44 
45 #ifndef TIN_H
46 #define TIN_H 1
47 
48 #ifdef HAVE_CONFIG_H
49 #	ifndef TIN_AUTOCONF_H
50 #		include <autoconf.h>	/* FIXME: normally we use 'config.h' */
51 #	endif /* !TIN_AUTOCONF_H */
52 #else
53 #	ifndef HAVE_CONFDEFS_H
54 #		error "configure run missing"
55 #	endif /* !HAVE_CONFDEFS_H */
56 #endif /* HAVE_CONFIG_H */
57 
58 
59 /*
60  * this causes trouble on Linux (forces nameserver lookups even for local
61  * connections - this is an (unwanted) feature of getaddrinfo) see also
62  * nntplib.c
63  */
64 /* IPv6 support */
65 #if defined(HAVE_GETADDRINFO) && defined(HAVE_GAI_STRERROR) && defined(ENABLE_IPV6)
66 #	define INET6
67 #endif /* HAVE_GETADDRINFO && HAVE_GAI_STRERROR && ENABLE_IPV6 */
68 
69 
70 /*
71  * Native Language Support.
72  */
73 #ifndef NO_LOCALE
74 #	ifdef HAVE_LOCALE_H
75 #		include <locale.h>
76 #	endif /* HAVE_LOCALE_H */
77 #	ifndef HAVE_SETLOCALE
78 #		define setlocale(Category, Locale) /* empty */
79 #	endif /* !HAVE_SETLOCALE */
80 #endif /* !NO_LOCALE */
81 
82 #define N_(Str) Str
83 
84 #if defined(ENABLE_NLS) && !defined(__BUILD__)
85 #	ifdef HAVE_LIBINTL_H
86 #		include <libintl.h>
87 #	endif /* HAVE_LIBINTL_H */
88 #	define _(Text)	gettext(Text)
89 #else
90 #	undef bindtextdomain
91 #	define bindtextdomain(Domain, Directory) /* empty */
92 #	undef textdomain
93 #	define textdomain(Domain) /* empty */
94 #	define _(Text) Text
95 #endif /* ENABLE_NLS && !__BUILD__ */
96 
97 #ifndef LOCALEDIR
98 #	define LOCALEDIR "/usr/share/locale"
99 #endif /* !LOCALEDIR */
100 
101 #if defined(__amiga__) || defined(__amiga)
102 #	define SMALL_MEMORY_MACHINE
103 #endif /* __amiga__ || __amiga */
104 
105 #include <signal.h>
106 
107 enum context { cMain, cArt, cAttachment, cAttrib, cConfig, cFilter, cGroup, cHelp, cInfopager, cPage, cPost, cPostCancel, cPostFup, cReconnect, cScope, cSelect, cThread, cURL };
108 enum icontext { cNone, cGetline, cPromptCONT, cPromptSLK, cPromptYN };
109 enum resizer { cNo, cYes, cRedraw };
110 enum rc_state { RC_IGNORE, RC_UPGRADE, RC_DOWNGRADE, RC_ERROR };
111 
112 #include <stdio.h>
113 #ifdef HAVE_ERRNO_H
114 #	include <errno.h>
115 #else
116 #	ifdef HAVE_SYS_ERRNO_H
117 #		include <sys/errno.h>
118 /*
119 	#	else
120 	#		error "No errno.h or sys/errno.h found"
121 */
122 #	endif /* HAVE_SYS_ERRNO_H */
123 #endif /* HAVE_ERRNO_H */
124 #if !defined(errno)
125 #	ifdef DECL_ERRNO
126 		extern int errno;
127 #	endif /* DECL_ERRNO */
128 #endif /* !errno */
129 #if !defined(EHOSTUNREACH)
130 #   define EHOSTUNREACH 113
131 #endif /* !EHOSTUNREACH */
132 
133 #ifdef HAVE_STDDEF_H
134 #	include <stddef.h>
135 #endif /* HAVE_STDDEF_H */
136 #ifdef HAVE_SYS_TYPES_H
137 #	include <sys/types.h>
138 #endif /* HAVE_SYS_TYPES_H */
139 
140 #ifdef HAVE_SYS_STAT_H
141 #	include <sys/stat.h>
142 #endif /* HAVE_SYS_STAT_H */
143 
144 #ifdef TIME_WITH_SYS_TIME
145 #	include <sys/time.h>
146 #	include <time.h>
147 #else
148 #	ifdef HAVE_SYS_TIME_H
149 #		include <sys/time.h>
150 #	else
151 #		include <time.h>
152 #	endif /* HAVE_SYS_TIME_H */
153 #endif /* TIME_WITH_SYS_TIME */
154 
155 #ifdef HAVE_SYS_TIMES_H
156 #	include <sys/times.h>
157 #endif /* HAVE_SYS_TIMES_H */
158 
159 #if defined(HAVE_LIBC_H) && defined(__NeXT__)
160 #	include <libc.h>
161 #endif /* HAVE_LIBC_H && __NeXT__ */
162 
163 #ifdef HAVE_UNISTD_H
164 #	include <unistd.h>
165 #endif /* HAVE_UNISTD_H */
166 
167 #ifdef HAVE_PWD_H
168 #	include <pwd.h>
169 #endif /* HAVE_PWD_H */
170 
171 #ifdef HAVE_SYS_PARAM_H
172 #	include <sys/param.h>
173 #endif /* HAVE_SYS_PARAM_H */
174 
175 #include <ctype.h>
176 
177 #ifdef HAVE_STDLIB_H
178 #	include <stdlib.h>
179 #endif /* HAVE_STDLIB_H */
180 
181 #include <stdarg.h>
182 
183 #ifdef HAVE_GETOPT_H
184 #	include <getopt.h>
185 #endif /* HAVE_GETOPT_H */
186 
187 #if defined(ENABLE_LONG_ARTICLE_NUMBERS) && !defined(SMALL_MEMORY_MACHINE)
188 /*
189  * defines and typedefs for 64 bit article numbers
190  *
191  * TODO: what if !CPP_DOES_CONCAT
192  *       add configure check for PRIdLEAST64
193  *       add configure check for SCNdLEAST64
194  */
195 #	if defined(HAVE_INT_LEAST64_T) && !defined(HAVE_INTTYPES_H)
196 #		undef HAVE_INT_LEAST64_T
197 #	endif /* HAVE_INT_LEAST64_T && !HAVE_INTTYPES_H */
198 #	if defined(HAVE_INT_LEAST64_T) || defined(HAVE_LONG_LONG) || defined(quad_t)
199 #		if defined(HAVE_ATOLL) || defined(HAVE_ATOQ)
200 #			ifdef HAVE_STRTOLL
201 #				define USE_LONG_ARTICLE_NUMBERS 1
202 #			endif /* HAVE_STRTOLL */
203 #		endif /* HAVE_ATOLL || HAVE_ATOQ */
204 #	endif /* HAVE_INT_LEAST64_T || HAVE_LONG_LONG || quad_t */
205 #	ifdef HAVE_STDINT_H
206 #		include <stdint.h>
207 #	endif	/* HAVE_STDINT_H */
208 #endif /* ENABLE_LONG_ARTICLE_NUMBERS && !SMALL_MEMORY_MACHINE */
209 #ifdef USE_LONG_ARTICLE_NUMBERS
210 #	if defined(HAVE_INT_LEAST64_T) && defined(HAVE_INT64_C)
211 #		include <inttypes.h>
212 		typedef int_least64_t t_artnum;
213 #		define T_ARTNUM_PFMT PRIdLEAST64
214 #		define T_ARTNUM_SFMT SCNdLEAST64
215 #		define T_ARTNUM_CONST(v) INT64_C(v)
216 #	else
217 		typedef long long t_artnum;
218 #		define T_ARTNUM_PFMT "lld"
219 #		define T_ARTNUM_SFMT "lld"
220 #		define T_ARTNUM_CONST(v) v ## LL
221 #	endif /* HAVE_INT_LEAST64_T && HAVE_INT64_C */
222 #	ifdef HAVE_ATOLL
223 #		define atoartnum atoll
224 #	else
225 #		define atoartnum atoq
226 #	endif /* HAVE_ATOLL */
227 #	define strtoartnum strtoll
228 #else
229 	typedef long t_artnum;
230 #	define T_ARTNUM_PFMT "ld"
231 #	define T_ARTNUM_SFMT "ld"
232 #	define T_ARTNUM_CONST(v) v ## L
233 #	define atoartnum atol
234 #	define strtoartnum strtol
235 #endif /* USE_LONG_ARTICLE_NUMBERS */
236 
237 /*
238  * FIXME: make this autoconf
239  */
240 #ifndef __QNX__
241 #	ifdef HAVE_STRING_H
242 #		include <string.h>
243 #	else
244 #		ifdef HAVE_STRINGS_H
245 #			include <strings.h>
246 #		endif /* HAVE_STRINGS_H */
247 #	endif /* HAVE_STRING_H */
248 #else
249 #	ifdef HAVE_STRING_H
250 #		include <string.h>
251 #	endif /* HAVE_STRING_H */
252 #	ifdef HAVE_STRINGS_H
253 #		include <strings.h>
254 #	endif /* HAVE_STRINGS_H */
255 #endif /* !__QNX__ */
256 
257 /*
258  * FIXME: make this autoconf
259  */
260 #ifdef SEIUX
261 #	include <bsd/sys/time.h>
262 #	include <bsd/sys/signal.h>
263 #	include <bsd/sys/types.h>
264 #	include <posix/unistd.h>
265 #	include <bsd/netinet/in.h>
266 #endif /* SEIUX */
267 /* *-next-nextstep3 && *-next-openstep4 */
268 #ifdef __NeXT__
269 #	undef HAVE_SYS_UTSNAME_H
270 #	undef HAVE_UNAME
271 #	undef WEXITSTATUS
272 #	undef WIFEXITED
273 #	define IGNORE_SYSTEM_STATUS 1
274 #	define HAVE_SYS_WAIT_H 1
275 #	define NO_LOCKING 1
276 #endif /* __NeXT__ */
277 /* m68k-sun-sunos3.5 */
278 #if defined(sun) || defined(__sun) && (!defined(__SVR4) || !defined(__svr4__)) && defined(BSD) && BSD < 199306
279 #	define IGNORE_SYSTEM_STATUS 1
280 #endif /* sun|| __sun && (!__SVR4 || __svr4__) && BSD && BSD < 199306 */
281 
282 #ifdef HAVE_FCNTL_H
283 #	include <fcntl.h>
284 #endif /* HAVE_FCNTL_H */
285 
286 #ifdef HAVE_SYS_IOCTL_H
287 #	include <sys/ioctl.h>
288 /* We don't need/use these, and they cause redefinition errors with SunOS 4.x
289  * when we include termio.h or termios.h
290  */
291 #	if defined(sun) && !defined(__svr4)
292 #		undef NL0
293 #		undef NL1
294 #		undef CR0
295 #		undef CR1
296 #		undef CR2
297 #		undef CR3
298 #		undef TAB0
299 #		undef TAB1
300 #		undef TAB2
301 #		undef XTABS
302 #		undef BS0
303 #		undef BS1
304 #		undef FF0
305 #		undef FF1
306 #		undef ECHO
307 #		undef NOFLSH
308 #		undef TOSTOP
309 #		undef FLUSHO
310 #		undef PENDIN
311 #	endif /* sun && !__svr4 */
312 #endif /* HAVE_SYS_IOCTL_H */
313 
314 #ifdef HAVE_PROTOTYPES_H
315 #	include <prototypes.h>
316 #endif /* HAVE_PROTOTYPES_H */
317 
318 #ifdef HAVE_SYS_UTSNAME_H
319 #	include <sys/utsname.h>
320 #endif /* HAVE_SYS_UTSNAME_H */
321 
322 /*
323  * Needed for catching child processes
324  */
325 #ifdef HAVE_SYS_WAIT_H
326 #	include <sys/wait.h>
327 #endif /* HAVE_SYS_WAIT_H */
328 
329 #ifndef WEXITSTATUS
330 #	define WEXITSTATUS(status)	((int) (((status) >> 8) & 0xFF))
331 #endif /* !WEXITSTATUS */
332 
333 #ifndef WIFEXITED
334 #	define WIFEXITED(status)	((int) (((status) & 0xFF) == 0))
335 #endif /* !WIFEXITED */
336 
337 /*
338  * Needed for timeout in user abort of indexing a group (BSD & SYSV variaties)
339  */
340 #ifdef HAVE_SYS_SELECT_H
341 #	ifdef NEED_TIMEVAL_FIX
342 #		define timeval fake_timeval
343 #		include <sys/select.h>
344 #		undef timeval
345 #	else
346 #		include <sys/select.h>
347 #	endif /* NEED_TIMEVAL_FIX */
348 #endif /* HAVE_SYS_SELECT_H */
349 
350 #if defined(HAVE_STROPTS_H) && !defined(__dietlibc__)
351 #	include <stropts.h>
352 #endif /* HAVE_STROPTS_H && !__dietlibc__ */
353 
354 #ifdef HAVE_POLL_H
355 #	include <poll.h>
356 #else
357 #	ifdef HAVE_SYS_POLL_H
358 #		include <sys/poll.h>
359 #	endif /* HAVE_SYS_POLL_H */
360 #endif /* HAVE_POLL_H */
361 
362 /*
363  * Directory handling code
364  */
365 #ifdef HAVE_DIRENT_H
366 #	include <dirent.h>
367 /* #	define NAMLEN(dirent) strlen((dirent)->d_name) */
368 #else
369 #	define dirent direct
370 /* #	define NAMLEN(dirent) (dirent)->d_namlen */
371 #	ifdef HAVE_SYS_NDIR_H
372 #		include <sys/ndir.h>
373 #	endif /* HAVE_SYS_NDIR_H */
374 #	ifdef HAVE_SYS_DIR_H
375 #		include <sys/dir.h>
376 #	endif /* HAVE_SYS_DIR_H */
377 #	ifdef HAVE_NDIR_H
378 #		include <ndir.h>
379 #	endif /* HAVE_NDIR_H */
380 #endif /* HAVE_DIRENT_H */
381 
382 #ifndef DIR_BUF
383 #	define DIR_BUF struct dirent
384 #endif /* !DIR_BUF */
385 
386 #ifndef HAVE_UNLINK
387 #	define unlink(file)	remove(file)
388 #endif /* !HAVE_UNLINK */
389 
390 /*
391  * If native OS hasn't defined STDIN_FILENO be a smartass and do it
392  */
393 #if !defined(STDIN_FILENO)
394 #	define STDIN_FILENO	0
395 #endif /* !STDIN_FILENO */
396 
397 /*
398  * include <paths.h> if available to define _PATH_TMP
399  */
400 #ifdef HAVE_PATHS_H
401 #	include <paths.h>
402 #endif /* HAVE_PATHS_H */
403 #ifndef _PATH_TMP
404 #	define _PATH_TMP	"/tmp/"
405 #endif /* _PATH_TMP */
406 
407 /*
408  * If OS misses the isascii() function
409  */
410 #if !defined(HAVE_ISASCII) && !defined(isascii)
411 #	define isascii(c) (!((c) & ~0177))
412 #endif /* !HAVE_ISASCII && !isascii */
413 
414 
415 /*
416  * any pgp/gpp support possible and wanted
417  * sort out possible conflicts: gpg is preferred over pgp5 over pgp
418  */
419 #if defined(HAVE_PGP) || defined(HAVE_PGPK) || defined(HAVE_GPG)
420 #	define HAVE_PGP_GPG 1
421 #	if defined(HAVE_PGP) && defined(HAVE_PGPK)
422 #		undef HAVE_PGP
423 #	endif /* HAVE_PGP && HAVE_PGPK */
424 #	if defined(HAVE_PGPK) && defined(HAVE_GPG)
425 #		undef HAVE_PGPK
426 #	endif /* HAVE_PGPK && HAVE_GPG */
427 #	if defined(HAVE_PGP) && defined(HAVE_GPG)
428 #		undef HAVE_PGP
429 #	endif /* HAVE_PGP && HAVE_GPG */
430 #endif /* HAVE_PGP || HAVE_PGPK || HAVE_GPG */
431 
432 /*
433  * slrnface requires some things
434  */
435 #if defined(HAVE_SLRNFACE) && defined(HAVE_MKFIFO) && defined(HAVE_FORK) && defined(HAVE_EXECLP) && defined(HAVE_WAITPID) && !defined(DONT_HAVE_PIPING) && !defined(X_DISPLAY_MISSING)
436 #	define XFACE_ABLE
437 #endif /* HAVE_SLRNFACE && HAVE_MKFIFO && HAVE_FORK && HAVE_EXECLP && HAVE_WAITPID && !DONT_HAVE_PIPING && !X_DISPLAY_MISSING */
438 
439 /*
440  * Setup support for reading from NNTP
441  */
442 #if defined(NNTP_ABLE) || defined(NNTP_ONLY)
443 #	ifndef NNTP_ABLE
444 #		define NNTP_ABLE	1
445 #	endif /* !NNTP_ABLE */
446 #	ifndef NNTP_INEWS
447 #		define NNTP_INEWS	1
448 #	endif /* !NNTP_INEWS */
449 #else
450 #	ifdef XHDR_XREF
451 #		undef XHDR_XREF
452 #	endif /* XHDR_XREF */
453 #	ifdef BROKEN_LISTGROUP
454 #		undef BROKEN_LISTGROUP
455 #	endif /* BROKEN_LISTGROUP */
456 #endif /* NNTP_ABLE || NNTP_ONLY */
457 
458 #define FAKE_NNTP_FP		(FILE *) 9999
459 
460 /*
461  * Max time between the first character of a VT terminal escape sequence
462  * for special keys and the following characters to arrive (msec)
463  */
464 #define SECOND_CHARACTER_DELAY	200
465 
466 /*
467  * Maximum time (seconds) for a VT terminal escape sequence
468  */
469 #define VT_ESCAPE_TIMEOUT	1
470 
471 /*
472  * Determine machine configuration for external programs & directories
473  */
474 #if defined(BSD)
475 /*
476  * To catch 4.3 Net2 code base or newer
477  * (e.g. FreeBSD 1.x, 4.3/Reno, NetBSD 0.9, 386BSD, BSD/386 1.1 and below).
478  * use
479  * #if (defined(BSD) && (BSD >= 199103))
480  *
481  * To detect if the code is being compiled on a 4.4 code base or newer
482  * (e.g. FreeBSD 2.x, 4.4, NetBSD 1.0, BSD/386 2.0 or above).
483  * use
484  * #if (defined(BSD) && (BSD >= 199306))
485  *
486  * (defined in <sys/param.h>)
487  */
488 #	ifndef HAVE_MEMCMP
489 #		define memcmp(s1, s2, n)	bcmp(s2, s1, n)
490 #	endif /* !HAVE_MEMCMP */
491 #	ifndef HAVE_MEMCPY
492 #		define memcpy(s1, s2, n)	bcopy(s2, s1, n)
493 #	endif /* !HAVE_MEMCPY */
494 #	ifndef HAVE_MEMSET
495 #		define memset(s1, s2, n)	bfill(s1, n, s2)
496 #	endif /* !HAVE_MEMSET */
497 #	ifndef HAVE_STRCHR
498 #		define strchr(str, ch)	index(str, ch)
499 #	endif /* !HAVE_STRCHR */
500 #	ifndef HAVE_STRRCHR
501 #		define strrchr(str, ch)	rindex(str, ch)
502 #	endif /* !HAVE_STRRCHR */
503 #	if defined(__386BSD__) || defined(__bsdi__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
504 #		define DEFAULT_PRINTER	"/usr/bin/lpr"
505 #		define DEFAULT_SUM	"/usr/bin/cksum -o 1 <" /* use tailing <, otherwise get filename output too */
506 #	else
507 #		define DEFAULT_PRINTER	"/usr/ucb/lpr"
508 #		define DEFAULT_SUM	"sum"
509 #	endif /* __386BSD__ || __bsdi__ || __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
510 #	ifdef DGUX
511 #		define USE_INVERSE_HACK
512 #	endif /* DGUX */
513 #	ifdef pyr
514 #		define DEFAULT_MAILER	"/usr/.ucbucb/mail"
515 #	endif /* pyr */
516 #else /* !BSD */
517 #	ifdef linux
518 #		define DEFAULT_PRINTER	"/usr/bin/lpr"
519 #	endif /* linux */
520 #	ifdef QNX42
521 #		ifndef DEFAULT_EDITOR
522 #			define DEFAULT_EDITOR	"/bin/vedit"
523 #		endif /* !DEFAULT_EDITOR */
524 #	endif /* QNX42 */
525 #	ifdef _AIX
526 #		define DEFAULT_PRINTER	"/bin/lp"
527 #		define READ_CHAR_HACK
528 #	endif /* _AIX */
529 #	ifdef sinix
530 #		define DEFAULT_PRINTER	"/bin/lpr"
531 #	endif /* sinix */
532 #	ifdef sysV68
533 #		define DEFAULT_MAILER	"/bin/rmail"
534 #	endif /* sysV68 */
535 #	ifdef UNIXPC
536 #		define DEFAULT_MAILER	"/bin/rmail"
537 #	endif /* UNIXPC */
538 
539 #	ifndef DEFAULT_PRINTER
540 #		define DEFAULT_PRINTER	"/usr/bin/lp"
541 #	endif /* !DEFAULT_PRINTER */
542 #	ifndef PATH_SUM
543 #		define DEFAULT_SUM	"sum -r"
544 #	endif /* !PATH_SUM */
545 #endif /* BSD */
546 
547 /*
548  * fallback values
549  */
550 #ifndef DEFAULT_EDITOR
551 #	define DEFAULT_EDITOR	"/usr/bin/vi"
552 #endif /* !DEFAULT_EDITOR */
553 #ifndef DEFAULT_MAILER
554 #	define DEFAULT_MAILER	"/usr/lib/sendmail"
555 #endif /* !DEFAULT_MAILER */
556 #ifndef DEFAULT_MAILBOX
557 #	define DEFAULT_MAILBOX	"/usr/spool/mail"
558 #endif /* !DEFAULT_MAILBOX */
559 
560 
561 /* FIXME: remove absolute-paths! */
562 /*
563  * Miscellaneous program-paths
564  */
565 #ifndef PATH_ISPELL
566 #	define PATH_ISPELL	"ispell"
567 #endif /* !PATH_ISPELL */
568 
569 #ifndef PATH_METAMAIL	/* only unset if !HAVE_METAMAIL */
570 #	define PATH_METAMAIL	"metamail"
571 #endif /* !PATH_METAMAIL */
572 #define METAMAIL_CMD		PATH_METAMAIL" -e -p -m \"tin\""
573 
574 #define INTERNAL_CMD	"--internal"
575 
576 /*
577  * Fix up the 'sum' path and parameter for './configure'd systems
578  */
579 #ifdef PATH_SUM
580 #	ifdef DEFAULT_SUM
581 #		undef DEFAULT_SUM
582 #	endif /* DEFAULT_SUM */
583 #	ifdef SUM_TAKES_DASH_R
584 #		define DEFAULT_SUM PATH_SUM_R
585 #	else
586 #		define DEFAULT_SUM PATH_SUM
587 #	endif /* SUM_TAKES_DASH_R */
588 #endif /* PATH_SUM */
589 
590 #ifdef HAVE_LONG_FILE_NAMES
591 #	define PATH_PART	"part"
592 #	define PATH_PATCH	"patch"
593 #	define INDEX_LOCK	"tin.%s.LCK"
594 #else
595 #	define PATH_PART	""
596 #	define PATH_PATCH	"p"
597 #	define INDEX_LOCK	"%s.LCK"
598 #endif /* HAVE_LONG_FILE_NAMES */
599 
600 /*
601  * How often should the active file be reread for new news
602  */
603 #ifndef REREAD_ACTIVE_FILE_SECS
604 #	define REREAD_ACTIVE_FILE_SECS 1200	/* seconds (20 mins) */
605 #endif /* !REREAD_ACTIVE_FILE_SECS */
606 
607 /*
608  * Initial sizes of internal arrays for small (<4MB) & large memory machines
609  */
610 #ifdef SMALL_MEMORY_MACHINE
611 #	define DEFAULT_ARTICLE_NUM	600
612 #	define DEFAULT_SAVE_NUM	10
613 #else
614 #	define DEFAULT_ARTICLE_NUM	1200
615 #	define DEFAULT_SAVE_NUM	30
616 #endif /* SMALL_MEMORY_MACHINE */
617 #define DEFAULT_ACTIVE_NUM	1800
618 #define DEFAULT_NEWNEWS_NUM	5
619 #define DEFAULT_MAPKEYS_NUM 100	/* ~remappable keys per level (avoid massiv reallocs) */
620 #define DEFAULT_SCOPE_NUM	8
621 
622 #define RCDIR	".tin"
623 #define INDEX_MAILDIR	".mail"
624 #define INDEX_NEWSDIR	".news"
625 #define INDEX_SAVEDIR	".save"
626 
627 #define ACTIVE_FILE	"active"
628 #define ACTIVE_MAIL_FILE	"active.mail"
629 #define ACTIVE_SAVE_FILE	"active.save"
630 #define ACTIVE_TIMES_FILE	"active.times"
631 #define ATTRIBUTES_FILE	"attributes"
632 #define CONFIG_FILE	"tinrc"
633 #define SERVERCONFIG_FILE	"serverrc"
634 #define DEFAULT_MAILDIR	"Mail"
635 #define DEFAULT_SAVEDIR	"News"
636 #define DEFAULT_URL_HANDLER "tinurl_handler.pl"
637 /* Prefixes saved attachments with no set filename */
638 #define SAVEFILE_PREFIX		"unknown"
639 
640 
641 /* MMDF-mailbox separator */
642 #ifndef MMDFHDRTXT
643 #	define MMDFHDRTXT "\01\01\01\01\n"
644 #endif /* MMDFHDRTXT */
645 
646 
647 /*
648  * all regexps are extended -> # must be quoted!
649  */
650 #ifdef HAVE_COLOR
651 /* case insensitive */
652 #	define DEFAULT_QUOTE_REGEX	"^\\s{0,3}(?:[\\]{}>|:)]|\\w{1,3}[>|])(?!-)"
653 #	define DEFAULT_QUOTE_REGEX2	"^\\s{0,3}(?:(?:[\\]{}>|:)]|\\w{1,3}[>|])\\s*){2}(?!-[})>])"
654 #	define DEFAULT_QUOTE_REGEX3	"^\\s{0,3}(?:(?:[\\]{}>|:)]|\\w{1,3}[>|])\\s*){3}"
655 #endif /* HAVE_COLOR */
656 
657 /* case insensitive */
658 #if 0 /* single words only */
659 #	define DEFAULT_SLASHES_REGEX	"(?:^|(?<=\\s))/[^\\s/]+/(?:(?=[,.!?;]?\\s)|$)"
660 #	define DEFAULT_STARS_REGEX	"(?:^|(?<=\\s))\\*[^\\s*]+\\*(?:(?=[,.!?;]?\\s)|$)"
661 #	define DEFAULT_UNDERSCORES_REGEX	"(?:^|(?<=\\s))_[^\\s_]+_(?:(?=[,.!?;]?\\s)|$)"
662 #	define DEFAULT_STROKES_REGEX	"(?:^|(?<=\\s))-[^-\\s]+-(?:(?=[,.!?;]?\\s)|$)"
663 #else /* multiple words */
664 #	define DEFAULT_SLASHES_REGEX	"(?:^|(?<=\\s))/(?(?=[^-*/_\\s][^/\\s])[^-*/_\\s][^/]*[^-*/_\\s]|[^/\\s])/(?:(?=[,.!?;]?\\s)|$)"
665 #	define DEFAULT_STARS_REGEX	"(?:^|(?<=\\s))\\*(?(?=[^-*/_\\s][^*\\s])[^-*/_\\s][^*]*[^-*/_\\s]|[^*\\s])\\*(?:(?=[,.!?;]?\\s)|$)"
666 #	define DEFAULT_UNDERSCORES_REGEX	"(?:^|(?<=\\s))_(?(?=[^-*/_\\s][^_\\s])[^-*/_\\s][^_]*[^-*/_\\s]|[^_\\s])_(?:(?=[,.!?;]?\\s)|$)"
667 #	define DEFAULT_STROKES_REGEX	"(?:^|(?<=\\s))-(?(?=[^-*/_\\s][^-\\s])[^-*/_\\s][^-]*[^-*/_\\s]|[^-\\s])-(?:(?=[,.!?;]?\\s)|$)"
668 #endif /* 0 */
669 
670 /* case sensitive && ^-anchored */
671 #define DEFAULT_STRIP_RE_REGEX	"(?:R[eE](?:\\^\\d+|\\[\\d+\\])?|A[wW]|Odp|Sv):\\s"
672 /* case sensitive */
673 #define DEFAULT_STRIP_WAS_REGEX	"(?:(?<=\\S)|\\s)\\((?:[Ww]a[rs]|[Bb]y[l\\xb3]o):.*\\)\\s*$"
674 #define DEFAULT_U8_STRIP_WAS_REGEX	"(?:(?<=\\S)|\\s)\\((?:[Ww]a[rs]|[Bb]y[l\\x{0142}]o):.*\\)\\s*$"
675 /*
676  * overkill regexp for balanced '()':
677  * #define DEFAULT_STRIP_WAS_REGEX	"(?:(?<=\\S)|\\s)\\((?:[Ww]a[rs]|[Bb]y[l\xb3]o):(?:(?:[^)(])*(?:\\([^)(]*\\))*)+\\)\\s*$"
678  */
679 
680 /* case sensitive & ^-anchored */
681 #define UUBEGIN_REGEX	"begin\\s\\s?[0-7]{3,4}\\s+"
682 /* case sensitive & ^-anchored */
683 #define UUBODY_REGEX	"(?:`|.[\\x20-\\x60]{1,61})$"
684 
685 /* case sensitive & ^-anchored */
686 #define SHAR_REGEX	"\\#(?:!\\s?(?:/usr)?/bin/sh|\\s?(?i)this\\sis\\sa\\sshell\\sarchive)"
687 
688 /* slrn verbatim marks, case sensitive & ^-anchored */
689 #define DEFAULT_VERBATIM_BEGIN_REGEX	"#v\\+\\s$"
690 #define DEFAULT_VERBATIM_END_REGEX	"#v-\\s$"
691 
692 /* quoted text from external sources */
693 #define DEFAULT_EXTQUOTE_REGEX "^\\|\\s"
694 
695 /*
696  * URL related regexs:
697  * add TELNET (RFC 4248), WAIS (RFC 4156), IMAP (RFC 2192), NFS (RFC 2224)
698  *     LDAP (RFC 2255), POP (RFC 2384)
699  * add IPv6 (RFC 2732, RFC 2373) support
700  */
701 /*
702  * case insensitive
703  * TODO: - split out ftp (only ftp allows username:passwd@, RFC 1738)?
704  *       - test IDNA (RFC 3490) case
705  */
706 #define URL_REGEX	"\\b(?:https?|ftp|gopher)://(?:[^:@/\\s]*(?::[^:@/\\s]*)?@)?(?:(?:(?:[^\\W_](?:(?:-|[^\\W_]){0,61}(?<!---)[^\\W_])?|xn--[^\\W_](?:-(?!-)|[^\\W_]){1,57}[^\\W_])\\.)+[a-z]{2,14}\\.?|localhost|(?:(?:2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(?:2[0-4]\\d|25[0-5]|[01]?\\d\\d?)|\\[(?:(?:[0-9A-F]{0,4}:){1,7}[0-9A-F]{1,4}|(?:[0-9A-F]{0,4}:){1,3}(?:(?:2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(?:2[0-4]\\d|25[0-5]|[01]?\\d\\d?))\\])(?::\\d+)?(?(?=[^\\)\\]\\>\"\\s]*\\()(?:/[^\\]\\>\"\\s]*|$|(?=[)\\]\\>\"\\s]))|(?:/[^)\\]\\>\"\\s]*|$|(?=[)\\]\\>\"\\s])))"
707 /*
708  * case insensitive
709  * TOFO: check against RFC 6068
710  */
711 #define MAIL_REGEX	"\\b(?:mailto:(?:[-\\w$.+!*'(),;/?:@&=]|%[\\da-f]{2})+)(?<!\\))"
712 /*
713  * case insensitive
714  * TODO: check against RFC 5538
715  */
716 #define NEWS_REGEX "\\b(?:s?news|nntp):(?:(?:(?://(?:(?:[^\\W_](?:(?:-|[^\\W_]){0,61}(?<!---)[^\\W_])?|xn--[^\\W_](?:-(?!-)|[^\\W_]){1,57}[^\\W_])\\.)+[a-z]{2,14}\\.?|localhost|(?:(?:2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(?:2[0-4]\\d|25[0-5]|[01]?\\d\\d?))(?::\\d+)?(?(?=[/])[^()\\^\\[\\]{}\\|\\x00-\\x1f\\x7f\\s\"<>'\\\\:,;]+|$))|[^\\^\\[\\]{}\\|\\x00-\\x1f\\x7f\\s<>\"():,;\\\\'/]+)\\b"
717 
718 #if 0 /* not implemented */
719 /*
720  * case insensitive
721  */
722 #	define TELNET_REGEX	"\\btelnet://(?:[^:@/]*(?::[^:@/]*)?@)?(?:(?:[^\\W_](?:(?:-|[^\\W_]){0,61}(?<!---)[^\\W_])?\\.)+[a-z]{2,14}\\.?||localhost|(?:(?:2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(?:2[0-4]\\d|25[0-5]|[01]?\\d\\d?))(?::\\d+)?/?"
723 #endif /* 0 */
724 
725 
726 #define FILTER_FILE	"filter"
727 #define INPUT_HISTORY_FILE	".inputhistory"
728 #ifdef HAVE_MH_MAIL_HANDLING
729 #	define MAILGROUPS_FILE	"mailgroups"
730 #endif /* HAVE_MH_MAIL_HANDLING */
731 #define NEWSRC_FILE	".newsrc"
732 #define NEWSRCTABLE_FILE	"newsrctable"
733 /* ifdef APPEND_PID (default) NEWNEWSRC_FILE will be .newnewsrc<pid> */
734 #define NEWNEWSRC_FILE	".newnewsrc"
735 #define OLDNEWSRC_FILE	".oldnewsrc"
736 #ifndef OVERVIEW_FILE
737 #	define OVERVIEW_FILE	".overview"
738 #endif /* !OVERVIEW_FILE */
739 #define OVERVIEW_FMT	"overview.fmt"
740 #define POSTED_FILE	"posted"
741 #define POSTPONED_FILE	"postponed.articles"
742 #define SUBSCRIPTIONS_FILE	"subscriptions"
743 #define NEWSGROUPS_FILE	"newsgroups"
744 #define KEYMAP_FILE	"keymap"
745 
746 #define SIGDASHES "-- \n"
747 
748 #ifndef BOOL_H
749 #	include "bool.h"
750 #endif /* BOOL_H */
751 
752 /* Philip Hazel's Perl regular expressions library */
753 #include <pcre.h>
754 
755 #ifdef HAVE_ICONV
756 #	define CHARSET_CONVERSION 1
757 #	ifdef HAVE_ICONV_H
758 #		include <iconv.h>
759 #	endif /* HAVE_ICONV_H */
760 #endif /* HAVE_ICONV */
761 
762 #ifdef HAVE_LANGINFO_H
763 #	include <langinfo.h>
764 #else
765 #	ifdef HAVE_NL_TYPES_H
766 #		include <nl_types.h>
767 #	endif /* HAVE_NL_TYPES_H */
768 #endif /* HAVE_LANGINFO_H */
769 #ifndef HAVE_NL_ITEM
770 	typedef int nl_item;
771 #endif /* HAVE_NL_ITEM */
772 #ifndef CODESET
773 #	define CODESET ((nl_item) 1)
774 #endif /* CODESET */
775 
776 #ifdef CHARSET_CONVERSION
777 #	define IS_LOCAL_CHARSET(c)	(!strncasecmp(tinrc.mm_local_charset, c, strlen(c)))
778 #else
779 #	define IS_LOCAL_CHARSET(c)	(!strncasecmp(tinrc.mm_charset, c, strlen(c)))
780 #endif /* CHARSET_CONVERSION */
781 
782 /* TODO: move up to the 'right' place */
783 #ifdef HAVE_SYS_FILE_H
784 #	include <sys/file.h>
785 #endif /* HAVE_SYS_FILE_H */
786 
787 #ifdef HAVE_LIBUTF8_H
788 #	include <libutf8.h>
789 #else
790 /*
791  * order is important here:
792  * - Solaris 2.5.1 requires wchar.h before wctype.h
793  * - Tru64 with Desktop Toolkit C requires stdio.h before wchar.h
794  * - BSD/OS 4.0.1 requires stddef.h, stdio.h and time.h before wchar.h
795  */
796 #	ifdef HAVE_WCHAR_H
797 #		include <wchar.h>
798 #	endif /* HAVE_WCHAR_H */
799 #	ifdef HAVE_WCTYPE_H
800 #		include <wctype.h>
801 #	endif /* HAVE_WCTYPE_H */
802 #endif /* HAVE_LIBUTF8_H */
803 
804 #ifndef MAX
805 #	define MAX(a,b)	(((a) > (b)) ? (a) : (b))
806 #endif /* !MAX */
807 #ifndef MIN
808 #	define MIN(a,b)	(((a) > (b)) ? (b) : (a))
809 #endif /* !MIN */
810 
811 #ifndef forever
812 /*@notfunction@*/
813 #	define forever	for(;;)
814 #endif /* !forever */
815 
816 /* safe strcpy into fixed-legth buffer */
817 #define STRCPY(dst, src)	(dst[sizeof(dst) - 1] = '\0', strncpy(dst, src, sizeof(dst) - 1))
818 
819 #define STRCMPEQ(s1, s2)	(strcmp((s1), (s2)) == 0)
820 #define STRNCMPEQ(s1, s2, n)	(strncmp((s1), (s2), n) == 0)
821 #define STRNCASECMPEQ(s1, s2, n)	(strncasecmp((s1), (s2), n) == 0)
822 
823 /*
824  * PATH_LEN    = max. path length (incl. terminating '\0')
825  * NAME_LEN    = max. filename length (not incl. terminating '\0')
826  * LEN         =
827  * HEADER_LEN  = max. size of a news/mail header-line
828  * NEWSRC_LINE =
829  */
830 
831 #ifdef PATH_MAX
832 #	define PATH_LEN	PATH_MAX
833 #else
834 #	ifdef MAXPATHLEN
835 #		define PATH_LEN	MAXPATHLEN
836 #	else
837 #		ifdef _POSIX_PATH_MAX
838 #			define PATH_LEN	_POSIX_PATH_MAX
839 #		else
840 #			define PATH_LEN	255
841 #		endif /* _POSIX_PATH_MAX */
842 #	endif /* MAXPATHLEN */
843 #endif /* PATH_MAX */
844 #ifdef HAVE_LONG_FILE_NAMES
845 #	ifdef NAME_MAX
846 #		define NAME_LEN	NAME_MAX
847 #	else
848 #		ifdef _POSIX_NAME_MAX
849 #			define NAME_LEN	_POSIX_NAME_MAX
850 #		else
851 #			define NAME_LEN	14
852 #		endif /* _POSIX_NAME_MAX */
853 #	endif /* NAME_MAX */
854 #else
855 #	define NAME_LEN	14
856 #endif /* HAVE_LONG_FILE_NAMES */
857 #define LEN	1024
858 
859 #define NEWSRC_LINE	8192
860 #define HEADER_LEN	1024
861 #define IMF_LINE_LEN 998 /* RFC 5322 2.1.1 */
862 
863 #define TABLE_SIZE	1409
864 
865 #define MODULO_COUNT_NUM	50
866 
867 #define DAY	(60*60*24)		/* Seconds in a day */
868 
869 #define ctrl(c)	((c) & 0x1F)
870 
871 #ifndef DEFAULT_ISO2ASC
872 #	define DEFAULT_ISO2ASC	"-1 "	/* ISO -> ASCII charset conversion */
873 #endif /* !DEFAULT_ISO2ASC */
874 
875 #ifndef DEFAULT_COMMENT
876 #	define DEFAULT_COMMENT	"> "	/* used when by follow-ups & replies */
877 #endif /* !DEFAULT_COMMENT */
878 #ifndef ART_MARK_UNREAD
879 #	define ART_MARK_UNREAD	'+'	/* used to show that an art is unread */
880 #endif /* !ART_MARK_UNREAD */
881 #ifndef ART_MARK_RETURN
882 #	define ART_MARK_RETURN	'-'	/* used to show that an art will return */
883 #endif /* !ART_MARK_RETURN */
884 #ifndef ART_MARK_SELECTED
885 #	define ART_MARK_SELECTED	'*'	/* used to show that an art was auto selected */
886 #endif /* !ART_MARK_SELECTED */
887 #ifndef ART_MARK_RECENT
888 #	define ART_MARK_RECENT	'o'	/* used to show that an art is fresh */
889 #endif /* !ART_MARK_RECENT */
890 #ifndef ART_MARK_READ
891 #	define ART_MARK_READ	' '	/* used to show that an art was not read or seen */
892 #endif /* !ART_MARK_READ */
893 #ifndef ART_MARK_READ_SELECTED
894 #	define ART_MARK_READ_SELECTED ':'	/* used to show that a read art is hot (kill_level >0) */
895 #endif /* !ART_MARK_READ_SELECTED */
896 #ifndef ART_MARK_KILLED
897 #	define ART_MARK_KILLED 'K'		/* art has been killed (kill_level >0) */
898 #endif /* !ART_MARK_KILLED */
899 #ifndef ART_MARK_DELETED
900 #	define ART_MARK_DELETED	'D'	/* art has been marked for deletion (mailgroup) */
901 #endif /* !ART_MARK_DELETED */
902 #ifndef MARK_INRANGE
903 #	define MARK_INRANGE	'#'	/* group/art within a range (# command) */
904 #endif /* !MARK_INRANGE */
905 
906 
907 /*
908  * Unicode chars for thread and attachment tree and cursor (instead of "|+`->")
909  * only available when IS_LOCAL_CHARSET("UTF-8")
910  */
911 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
912 	/*
913 	 * For CURSOR_ARROW and CURSOR_HORIZ tinrc.utf8_graphics ? :
914 	 * is handled inside screen.c:draw_arrow_mark().
915 	 */
916 #	define CURSOR_ARROW		(wint_t) 0x25B6
917 #	define CURSOR_HORIZ		(wint_t) 0x2500
918 #	define TREE_ARROW		(wchar_t) (tinrc.utf8_graphics ? 0x25B6 : '>')
919 #	define TREE_ARROW_WRAP	(wchar_t) (tinrc.utf8_graphics ? 0x25B7 : '>')
920 #	define TREE_BLANK		(wchar_t) ' '
921 #	define TREE_HORIZ		(wchar_t) (tinrc.utf8_graphics ? 0x2500 : '-')
922 #	define TREE_UP_RIGHT	(wchar_t) (tinrc.utf8_graphics ? 0x2514 : '`')
923 #	define TREE_VERT		(wchar_t) (tinrc.utf8_graphics ? 0x2502 : '|')
924 #	define TREE_VERT_RIGHT	(wchar_t) (tinrc.utf8_graphics ? 0x251C : '+')
925 #else
926 	/*
927 	 * No need for CURSOR_ARROW and CURSOR_HORIZ here. This is handled inside
928 	 * screen.c:draw_arrow_mark().
929 	 */
930 #	define TREE_ARROW		'>'
931 #	define TREE_ARROW_WRAP	'>'
932 #	define TREE_BLANK		' '
933 #	define TREE_HORIZ		'-'
934 #	define TREE_UP_RIGHT	'`'
935 #	define TREE_VERT		'|'
936 #	define TREE_VERT_RIGHT	'+'
937 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
938 
939 #ifdef USE_INVERSE_HACK
940 #	define BLANK_PAGE_COLS	2
941 #else
942 #	define BLANK_PAGE_COLS	0
943 #endif /* USE_INVERSE_HACK */
944 
945 /*
946  * Return values for tin_errno
947  */
948 #define TIN_ABORT		1			/* User requested abort or timeout */
949 
950 #define TINRC_CONFIRM_ACTION	(tinrc.confirm_choice == 1 || tinrc.confirm_choice == 4 || tinrc.confirm_choice == 5 || tinrc.confirm_choice == 7)
951 #define TINRC_CONFIRM_TO_QUIT	(tinrc.confirm_choice == 3 || tinrc.confirm_choice == 4 || tinrc.confirm_choice == 6 || tinrc.confirm_choice == 7)
952 #define TINRC_CONFIRM_SELECT	(tinrc.confirm_choice == 2 || tinrc.confirm_choice == 5 || tinrc.confirm_choice == 6 || tinrc.confirm_choice == 7)
953 #define TINRC_CONFIRM_MAX	7
954 
955 /*
956  * defines for tinrc.auto_cc_bcc
957  */
958 #define AUTO_CC					1
959 #define AUTO_BCC				2
960 #define AUTO_CC_BCC				3
961 
962 /*
963  * defines for tinrc.goto_next_unread
964  */
965 #define NUM_GOTO_NEXT_UNREAD	4
966 #define GOTO_NEXT_UNREAD_PGDN	1
967 #define GOTO_NEXT_UNREAD_TAB	2
968 
969 /*
970  * defines for tinrc.trim_article_body
971  */
972 #define NUM_TRIM_ARTICLE_BODY	8
973 #define SKIP_LEADING			1
974 #define SKIP_TRAILING			2
975 #define COMPACT_MULTIPLE		4
976 
977 /*
978  * MIME Encodings
979  */
980 enum {
981 	MIME_ENCODING_8BIT = 0,
982 	MIME_ENCODING_BASE64,
983 	MIME_ENCODING_QP,
984 	MIME_ENCODING_7BIT
985 };
986 
987 /*
988  * Number of charset-traslation tables (iso2asci)
989  */
990 #define NUM_ISO_TABLES	7
991 
992 /*
993  * Maximum permissible colour number
994  */
995 #define MAX_COLOR	15
996 #define MAX_BACKCOLOR	7
997 
998 /*
999  * Count of available attributes for highlighting
1000  */
1001 #define MAX_ATTR	6
1002 
1003 /*
1004  * Maximal permissible word mark type
1005  * 0 = nothing, 1 = mark, 2 = space
1006  */
1007 #define MAX_MARK	2
1008 
1009 /* Line number (starting at 0) of 1st non-header data on the screen */
1010 /* ie, size of header */
1011 #define INDEX_TOP	2
1012 #define INDEX2LNUM(i)	(INDEX_TOP + (i) - currmenu->first)
1013 #ifndef USE_CURSES
1014 #	define INDEX2SNUM(i)	((i) - currmenu->first)
1015 #endif /* !USE_CURSES */
1016 
1017 #define GROUP_MATCH(s1, pat, case_s)		(wildmat(s1, pat, case_s))
1018 
1019 #define REGEX_FMT (tinrc.wildcard ? "%s" : "*%s*")
1020 
1021 #define IGNORE_ART(i)	((tinrc.kill_level != KILL_THREAD && arts[i].killed) || (arts[i].thread == ART_EXPIRED))
1022 /* only used for threading */
1023 #define IGNORE_ART_THREAD(i)	(arts[i].thread != ART_UNTHREADED || (tinrc.kill_level == KILL_NOTHREAD && arts[i].killed))
1024 
1025 /*
1026  * Is this part text/plain?
1027  */
1028 #define IS_PLAINTEXT(x) \
1029 			(x->type == TYPE_TEXT && strcasecmp("plain", x->subtype) == 0)
1030 
1031 /* TRUE if basenote has responses */
1032 #define HAS_FOLLOWUPS(i)	(arts[base[i]].thread >= 0)
1033 
1034 /*
1035  * Only close off our stream when reading on local spool
1036  */
1037 #ifdef NNTP_ABLE
1038 #	define TIN_FCLOSE(x)	if (x != FAKE_NNTP_FP) fclose(x)
1039 #else
1040 #	define TIN_FCLOSE(x)	fclose(x)
1041 #endif /* NNTP_ABLE */
1042 
1043 /*
1044  * Often used macro to point to the group we are currently in
1045  */
1046 #define CURR_GROUP	(active[my_group[selmenu.curr]])
1047 
1048 /*
1049  * Defines an unread group
1050  */
1051 #define UNREAD_GROUP(i)		(!active[my_group[i]].bogus && active[my_group[i]].newsrc.num_unread > 0)
1052 
1053 /*
1054  * Expands to singular/plural version of string
1055  */
1056 #define PLURAL(x,y)			((x == 1) ? _(y##_singular) : _(y##_plural))
1057 
1058 /*
1059  * News/Mail group types
1060  */
1061 #define GROUP_TYPE_MAIL	0
1062 #define GROUP_TYPE_NEWS	1
1063 #define GROUP_TYPE_SAVE	2	/* saved news, read with tin -R */
1064 
1065 /*
1066  * used by get_arrow_key()
1067  */
1068 #	define KEYMAP_UNKNOWN		0
1069 #	define KEYMAP_UP		1
1070 #	define KEYMAP_DOWN		2
1071 #	define KEYMAP_LEFT		3
1072 #	define KEYMAP_RIGHT		4
1073 #	define KEYMAP_PAGE_UP		5
1074 #	define KEYMAP_PAGE_DOWN	6
1075 #	define KEYMAP_HOME		7
1076 #	define KEYMAP_END		8
1077 #	define KEYMAP_DEL		9
1078 #	define KEYMAP_INS		10
1079 #	define KEYMAP_MOUSE		11
1080 
1081 
1082 /*
1083  * used in curses.c and signal.c
1084  * it's useless trying to run tin below these sizes
1085  * (values acquired by testing ;-) )
1086  */
1087 #define MIN_LINES_ON_TERMINAL		 8
1088 #define MIN_COLUMNS_ON_TERMINAL		50
1089 
1090 
1091 /*
1092  * indicate given cmd-line options
1093  */
1094 #define CMDLINE_GETART_LIMIT	1
1095 #define CMDLINE_MAILDIR			2
1096 #define CMDLINE_NNTPSERVER		4
1097 #define CMDLINE_SAVEDIR			8
1098 #define CMDLINE_USE_COLOR		16
1099 
1100 
1101 /*
1102  * used by feed_articles() & show_mini_help() & quick_filter & add_filter_rule
1103  */
1104 #define SELECT_LEVEL	1
1105 #define GROUP_LEVEL	2
1106 #define THREAD_LEVEL	3
1107 #define PAGE_LEVEL	4
1108 #define INFO_PAGER	5
1109 #define SCOPE_LEVEL	6
1110 #define CONFIG_LEVEL	7
1111 #define ATTRIB_LEVEL	8
1112 #define ATTACHMENT_LEVEL	9
1113 #define URL_LEVEL	10
1114 
1115 #define MINI_HELP_LINES		5
1116 
1117 #define FEED_MAIL		1
1118 #define FEED_PIPE		2
1119 #define FEED_PRINT		3
1120 #define FEED_SAVE		4
1121 #define FEED_AUTOSAVE	5
1122 #define FEED_REPOST		6
1123 #define FEED_MARK_READ		7
1124 #define FEED_MARK_UNREAD	8
1125 
1126 
1127 /*
1128  * Threading strategies available
1129  */
1130 #define THREAD_NONE		0
1131 #define THREAD_SUBJ		1
1132 #define THREAD_REFS		2
1133 #define THREAD_BOTH		3
1134 #define THREAD_MULTI		4
1135 #define THREAD_PERC		5
1136 
1137 #define THREAD_MAX		THREAD_PERC
1138 
1139 #define THREAD_PERC_DEFAULT	75
1140 
1141 /*
1142  * Values for show_author
1143  */
1144 #define SHOW_FROM_NONE		0
1145 #define SHOW_FROM_ADDR		1
1146 #define SHOW_FROM_NAME		2
1147 #define SHOW_FROM_BOTH		3
1148 
1149 /*
1150  * Values for thread_score
1151  */
1152 #define THREAD_SCORE_MAX	0
1153 #define THREAD_SCORE_SUM	1
1154 #define THREAD_SCORE_WEIGHT	2
1155 
1156 /*
1157  * Values for interactive_mailer
1158  */
1159 enum {
1160 	INTERACTIVE_NONE = 0,
1161 	INTERACTIVE_WITH_HEADERS,
1162 	INTERACTIVE_WITHOUT_HEADERS
1163 };
1164 
1165 /*
1166  * used in feed.c & save.c
1167  */
1168 #define POST_PROC_NO		0
1169 #define POST_PROC_SHAR		1
1170 #define POST_PROC_YES		2
1171 
1172 /*
1173  * used in art.c
1174  * sort types on arts[] array
1175  */
1176 #define SORT_ARTICLES_BY_NOTHING		0
1177 #define SORT_ARTICLES_BY_SUBJ_DESCEND	1
1178 #define SORT_ARTICLES_BY_SUBJ_ASCEND	2
1179 #define SORT_ARTICLES_BY_FROM_DESCEND	3
1180 #define SORT_ARTICLES_BY_FROM_ASCEND	4
1181 #define SORT_ARTICLES_BY_DATE_DESCEND	5
1182 #define SORT_ARTICLES_BY_DATE_ASCEND	6
1183 #define SORT_ARTICLES_BY_SCORE_DESCEND	7
1184 #define SORT_ARTICLES_BY_SCORE_ASCEND	8
1185 #define SORT_ARTICLES_BY_LINES_DESCEND	9
1186 #define SORT_ARTICLES_BY_LINES_ASCEND	10
1187 
1188 /*
1189  * used in art.c
1190  * sort types on base[] array
1191  */
1192 #define SORT_THREADS_BY_NOTHING			0
1193 #define SORT_THREADS_BY_SCORE_DESCEND	1
1194 #define SORT_THREADS_BY_SCORE_ASCEND	2
1195 #define SORT_THREADS_BY_LAST_POSTING_DATE_DESCEND	3
1196 #define SORT_THREADS_BY_LAST_POSTING_DATE_ASCEND	4
1197 
1198 /*
1199  * Different values of strip_bogus - the ways to handle bogus groups
1200  */
1201 #define BOGUS_KEEP		0	/* not used */
1202 #define BOGUS_REMOVE		1
1203 #define BOGUS_SHOW		2
1204 
1205 /*
1206  * Different extents to which we can hide killed articles
1207  */
1208 #define KILL_UNREAD		0		/* Kill only unread articles */
1209 #define KILL_THREAD		1		/* Kill all articles and show as K */
1210 #define KILL_NOTHREAD	2		/* Kill all articles, never show them */
1211 
1212 /*
1213  * Various types of quoting behaviour
1214  */
1215 #define QUOTE_COMPRESS	1		/* Compress quotes */
1216 #define QUOTE_SIGS		2		/* Quote signatures */
1217 #define QUOTE_EMPTY		4		/* Quote empty lines */
1218 
1219 
1220 /*
1221  * used in save.c/main.c
1222  */
1223 #define CHECK_ANY_NEWS		0
1224 #define START_ANY_NEWS		1
1225 #define MAIL_ANY_NEWS		2
1226 #define SAVE_ANY_NEWS		3
1227 
1228 
1229 /*
1230  * used in post.c
1231  */
1232 #define POSTED_NONE		0			/* Article wasn't posted */
1233 #define POSTED_REDRAW		1			/* redraw needed in any case */
1234 #define POSTED_OK		2			/* posted normally */
1235 
1236 
1237 /*
1238  * used in pager
1239  */
1240 #define UUE_NO			0		/* Don't hide uue data */
1241 #define UUE_YES			1		/* Hide uue data */
1242 #define UUE_ALL			2		/* Hide uue data harder */
1243 
1244 /*
1245  * used in misc.c/rfc1524.c
1246  */
1247 enum quote_enum {
1248 	no_quote = 0,
1249 	dbl_quote,
1250 	sgl_quote
1251 };
1252 
1253 
1254 /*
1255  * index_point variable values used throughout tin
1256  */
1257 
1258 /*
1259  * -1 is kind of overloaded as an error from which_thread() and other functions
1260  * where we wish to return to the next level up
1261  */
1262 enum {
1263 	GRP_RETSELECT	= -1,	/* Pager 'T' command only -> return to selection screen */
1264 	GRP_QUIT		= -2,	/* Set by 'Q' when coming all the way out */
1265 	GRP_NEXTUNREAD	= -3,	/* (After catchup) goto next unread item */
1266 	GRP_NEXT		= -4,	/* (After catchup) move to next item */
1267 	GRP_ARTUNAVAIL	= -5,	/* show_page() Article is unavailable */
1268 	GRP_ARTABORT	= -6,	/* show_page() User aborted article read */
1269 	GRP_KILLED		= -7,	/* ?? Thread was killed at pager level */
1270 	GRP_GOTOTHREAD	= -8,	/* show_page() only. Goto thread menu */
1271 	GRP_ENTER		= -9,	/* New group is set, spin in read_groups() */
1272 	GRP_EXIT		= -10	/* Normal return to higher level */
1273 };
1274 
1275 #ifndef EXIT_SUCCESS
1276 #	define EXIT_SUCCESS	0	/* Successful exit status */
1277 #endif /* !EXIT_SUCCESS */
1278 
1279 #ifndef EXIT_FAILURE
1280 #	define EXIT_FAILURE	1	/* Failing exit status */
1281 #endif /* !EXIT_FAILURE */
1282 
1283 #define NEWS_AVAIL_EXIT 2
1284 #define NNTP_ERROR_EXIT	3
1285 
1286 /*
1287  * Assertion verifier
1288  */
1289 #ifdef assert
1290 #	undef assert
1291 #endif /* assert */
1292 #ifdef NDEBUG
1293 #	define assert(p)        ((void) 0)
1294 #else
1295 #	ifdef CPP_DOES_EXPAND
1296 #		define assert(p)	if(!(p)) asfail(__FILE__, __LINE__, #p); else (void) 0;
1297 #	else
1298 #		define assert(p)	if(!(p)) asfail(__FILE__, __LINE__, "p"); else (void) 0;
1299 #	endif /* CPP_DOES_EXPAND */
1300 #endif /* NDEBUG */
1301 
1302 #define ESC	27
1303 
1304 /*
1305  * filter entries expire after DEFAULT_FILTER_DAYS
1306  */
1307 #define DEFAULT_FILTER_DAYS		28
1308 
1309 /*
1310  * art.thread
1311  */
1312 #define ART_UNTHREADED	-1
1313 #define ART_EXPIRED		-2
1314 
1315 /*
1316  * Where does this belong?? It is overloaded
1317  */
1318 #define ART_NORMAL		-1
1319 
1320 /*
1321  * art.status
1322  */
1323 #define ART_READ		0
1324 #define ART_UNREAD		1
1325 #define ART_WILL_RETURN		2
1326 #define ART_UNAVAILABLE		-1 /* Also used by msgid.article */
1327 
1328 /*
1329  * art.killed
1330  */
1331 #define ART_NOTKILLED		0
1332 #define ART_KILLED		1
1333 #define ART_KILLED_UNREAD	2
1334 
1335 /*
1336  * Additionally used for user aborts in art_open()
1337  */
1338 #define ART_ABORT		-2
1339 
1340 /*
1341  * used by t_group & my_group[]
1342  */
1343 #define UNSUBSCRIBED	'!'
1344 #define SUBSCRIBED	':'
1345 
1346 /* Converts subscription status to char for .newsrc */
1347 #define SUB_CHAR(x)	(x ? SUBSCRIBED : UNSUBSCRIBED)
1348 /* Converts .newsrc subscription char to boolean */
1349 #define SUB_BOOL(x)	(x == SUBSCRIBED)
1350 
1351 /*
1352  * filter_type used in struct t_filter
1353  */
1354 #define SCORE_MAX		10000
1355 
1356 #define FILTER_SUBJ_CASE_SENSITIVE		0
1357 #define FILTER_SUBJ_CASE_IGNORE		1
1358 #define FILTER_FROM_CASE_SENSITIVE		2
1359 #define FILTER_FROM_CASE_IGNORE		3
1360 #define FILTER_MSGID		4
1361 #define FILTER_MSGID_LAST	5
1362 #define FILTER_MSGID_ONLY	6
1363 #define FILTER_REFS_ONLY	7
1364 #define FILTER_LINES		8
1365 
1366 #define FILTER_LINES_NO		0
1367 #define FILTER_LINES_EQ		1
1368 #define FILTER_LINES_LT		2
1369 #define FILTER_LINES_GT		3
1370 
1371 /*
1372  * default format strings for selection, group, thread level
1373  * and the date display in the page header.
1374  * Don't change without adjusting rc_update() and the like accordingly!
1375  */
1376 #define DEFAULT_SELECT_FORMAT	"%f %n %U  %G  %d"
1377 #define DEFAULT_GROUP_FORMAT	"%n %m %R %L  %s  %F"
1378 #define DEFAULT_THREAD_FORMAT	"%n %m  [%L]  %T  %F"
1379 #define DEFAULT_DATE_FORMAT		"%a, %d %b %Y %H:%M:%S"
1380 
1381 /*
1382  * unicode normalization
1383  */
1384 #if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
1385 #	ifdef HAVE_LIBICUUC
1386 #		define HAVE_UNICODE_NORMALIZATION 3
1387 #	else
1388 #		ifdef HAVE_LIBUNISTRING
1389 #			define HAVE_UNICODE_NORMALIZATION 2
1390 #		else
1391 #			if defined(HAVE_LIBIDN) && defined(HAVE_STRINGPREP_H)
1392 #				define HAVE_UNICODE_NORMALIZATION 1
1393 #			endif /* HAVE_LIBIDN && HAVE_STRINGPREP_H */
1394 #		endif /* HAVE_LIBUNISTRING */
1395 #	endif /* HAVE_LIBICUUC */
1396 #endif /* MULTIBYTE_ABLE && !NO_LOCALE */
1397 
1398 /*
1399  * normalization forms, we prefer NFC (see RFC 6532) if possible
1400  */
1401 #ifdef HAVE_UNICODE_NORMALIZATION
1402 enum {
1403 	NORMALIZE_NONE = 0,
1404 	NORMALIZE_NFKC = 1,
1405 #	if (HAVE_UNICODE_NORMALIZATION >= 2)
1406 	NORMALIZE_NFKD = 2,
1407 	NORMALIZE_NFC = 3,
1408 	NORMALIZE_NFD = 4
1409 #		ifdef HAVE_UNICODE_UNORM2_H
1410 	, NORMALIZE_NFKC_CF = 5
1411 #		endif /* HAVE_UNICODE_UNORM2_H */
1412 #	endif /* HAVE_UNICODE_NORMALIZATION >= 2 */
1413 };
1414 #	if (HAVE_UNICODE_NORMALIZATION >= 2)
1415 #		ifdef HAVE_UNICODE_UNORM2_H
1416 #			define NORMALIZE_MAX NORMALIZE_NFKC_CF
1417 #		else
1418 #			define NORMALIZE_MAX NORMALIZE_NFD
1419 #		endif /* HAVE_UNICODE_UNORM2_H */
1420 #		define DEFAULT_NORMALIZE NORMALIZE_NFC
1421 #	else
1422 #		define NORMALIZE_MAX NORMALIZE_NFKC
1423 #		define DEFAULT_NORMALIZE NORMALIZE_NFKC
1424 #	endif /* HAVE_UNICODE_NORMALIZATION >= 2 */
1425 #endif /* HAVE_UNICODE_NORMALIZATION */
1426 
1427 #ifdef HAVE_LIBICUUC
1428 #	ifdef HAVE_UNICODE_USTRING_H
1429 #		include <unicode/ustring.h>
1430 #	endif /* HAVE_UNICODE_USTRING_H */
1431 #	ifdef HAVE_UNICODE_UNORM2_H
1432 #		include <unicode/unorm2.h>
1433 #	else
1434 #		ifdef HAVE_UNICODE_UNORM_H
1435 #			include <unicode/unorm.h>
1436 #		endif /* HAVE_UNICODE_UNORM_H */
1437 #	endif /* HAVE_UNICODE_UNORM2_H */
1438 #	ifdef HAVE_UNICODE_UIDNA_H
1439 #		include <unicode/uidna.h>
1440 #	endif /* HAVE_UNICODE_UIDNA_H */
1441 #	ifdef HAVE_UNICODE_UBIDI_H
1442 #		include <unicode/ubidi.h>
1443 #	endif /* HAVE_UNICODE_UBIDI_H */
1444 #endif /* HAVE_LIBICUUC */
1445 
1446 
1447 /*
1448  * used in checking article header before posting
1449  */
1450 #define MAX_COL		78	/* Max. line length before issuing a warning */
1451 #define MAX_SIG_LINES	4	/* Max. num. of signature lines before warning */
1452 
1453 typedef unsigned char	t_bitmap;
1454 
1455 /*
1456  * Keys for add_msgid()
1457  */
1458 #define REF_REF				1		/* Add a ref->ref entry */
1459 #define MSGID_REF			2		/* Add a msgid->ref entry */
1460 
1461 /*
1462  * Size of hash tables for hash_str() and hash_msgid()
1463  * Make sure it's prime!
1464  */
1465 #ifdef SMALL_MEMORY_MACHINE
1466 #	define HASHNODE_TABLE_SIZE 2411
1467 #	define MSGID_HASH_SIZE	2609
1468 #else
1469 #	define HASHNODE_TABLE_SIZE 222199
1470 #	define MSGID_HASH_SIZE	222199
1471 #endif /* MSGID_HASH_SIZE */
1472 
1473 /*
1474  * cmd-line options
1475  */
1476 struct t_cmdlineopts {
1477 	int getart_limit;			/* getart_limit */
1478 	char maildir[PATH_LEN];		/* maildir */
1479 	char nntpserver[PATH_LEN];	/* nntpserver */
1480 	char savedir[PATH_LEN];		/* savedir */
1481 	unsigned int args:5;		/* given options */
1482 };
1483 
1484 /*
1485  * Archive-Name: header
1486  */
1487 struct t_archive {
1488 	char *name;			/* name of archive */
1489 	char *partnum;			/* part/patch no. in archive */
1490 	t_bool ispart:1;		/* TRUE if part, FALSE if patch */
1491 };
1492 
1493 /*
1494  * struct t_msgid - message id
1495  */
1496 struct t_msgid {
1497 	struct t_msgid *next;		/* Next in hash chain */
1498 	struct t_msgid *parent;		/* Message-id followed up to */
1499 	struct t_msgid *sibling;	/* Next followup to parent */
1500 	struct t_msgid *child;		/* First followup to this article */
1501 	int article;			/* index in arts[] or ART_NORMAL */
1502 	char txt[1];			/* The actual msgid */
1503 };
1504 
1505 /*
1506  * struct t_article - article header
1507  *
1508  * article.thread:
1509  * the next article in thread
1510  *	-1  (ART_UNTHREADED) article exists but is not (yet) threaded
1511  *	-2  (ART_EXPIRED) article has expired (wasn't found in search of spool
1512  *	    directory for the group)
1513  *	>=0 points to another arts[] (struct t_article)
1514  *
1515  * article.prev:
1516  *	the previous article in thread
1517  *	-1  (ART_NORMAL) initial default, first (no previous) article in thread
1518  *	>=0 points to the previous arts[] (struct t_article)
1519  */
1520 struct t_article {
1521 	t_artnum artnum;		/* Article number in spool directory for group */
1522 	char *subject;			/* Subject: line from mail header */
1523 	char *from;			/* From: line from mail header (address) */
1524 	char *name;			/* From: line from mail header (full name) */
1525 	char *xref;			/* Xref: cross posted article reference line */
1526 	char *path;			/* Path: line */
1527 	/* NB: The msgid and refs are only retained until the reference tree is built */
1528 	char *msgid;			/* Message-ID: unique message identifier */
1529 	char *refs;			/* References: article reference id's */
1530 	struct t_msgid *refptr;		/* Pointer to us in the reference tree */
1531 	struct t_archive *archive;	/* Archive-Name: header */
1532 	time_t date;			/* Date: line from header in seconds */
1533 	int line_count;			/* Lines: number of lines in article */
1534 	int gnksa_code;			/* From: line from mail header (GNKSA error code) */
1535 	int tagged;			/* 0 = not tagged, >0 = tagged */
1536 	int thread;
1537 	int prev;
1538 	int score;			/* score article has reached after filtering */
1539 	unsigned int status:2;	/* 0 = read, 1 = unread, 2 = will return */
1540 	unsigned int killed:2;	/* 0 = not killed, 1 = killed, 2 = killed unread */
1541 	t_bool zombie:1;	/* 1 = was alive (unread) before 'X' command */
1542 	t_bool delete_it:1;	/* 1 = delete art when leaving group [mail group] */
1543 	t_bool selected:1;	/* FALSE = not selected, TRUE = selected */
1544 	t_bool inrange:1;	/* TRUE = article selected via # range command */
1545 	t_bool matched:1;	/* TRUE = article matched regex in feed.c */
1546 	t_bool keep_in_base:1;	/* TRUE = keep (read) article in base[] (show_only_unread_arts) */
1547 	t_bool multipart_subj:1;	/* TRUE = subject looks like multipart subject */
1548 };
1549 
1550 
1551 #ifdef NNTP_ABLE
1552 /*
1553  * struct t_article_range - holds ranges of article numbers to perform actions on parts of arts[]
1554  */
1555 struct t_article_range {
1556 	t_artnum start;
1557 	t_artnum end;
1558 	t_artnum cnt;
1559 	struct t_article_range *next;
1560 };
1561 #endif /* NNTP_ABLE */
1562 
1563 
1564 /*
1565  * struct t_newsheader - holds an array of which news headers to [not] display
1566  */
1567 struct t_newsheader {
1568 	char **header;	/* array of which headers to [not] display */
1569 	int num;		/* number of headers in array header */
1570 };
1571 
1572 /*
1573  * struct t_attribute - configurable attributes on a per group basis
1574  */
1575 struct t_attribute {
1576 	char *maildir;				/* mail dir if other than ~/Mail */
1577 	char *savedir;				/* save dir if other than ~/News */
1578 	char *savefile;				/* save articles to specified file */
1579 	char *sigfile;				/* sig file if other than ~/.Sig */
1580 	char *group_format;			/* format string for group level */
1581 	char *thread_format;		/* format string for thread level */
1582 	char *date_format;			/* format string for the date display */
1583 	char *editor_format;		/* editor + parameters  %E +%N %F */
1584 	char *organization;			/* organization name */
1585 	char *fcc;					/* Fcc folder for mail */
1586 	char *followup_to;			/* where posts should be redirected */
1587 	char *quick_kill_scope;		/* quick filter kill scope */
1588 	char *quick_select_scope;	/* quick filter select scope */
1589 	char *mailing_list;			/* mail list email address */
1590 	char *news_headers_to_display;	/* which headers to display */
1591 	char *news_headers_to_not_display;	/* which headers to not display */
1592 	char *x_headers;			/* extra headers for message header */
1593 	char *x_body;				/* boilerplate text for message body */
1594 	char *from;					/* from line */
1595 	char *news_quote_format;	/* another way to begin a posting format */
1596 	char *quote_chars;			/* string to precede quoted text on each line */
1597 	char *mime_types_to_save;	/* MIME content major/minors we want to save */
1598 #ifdef HAVE_ISPELL
1599 	char *ispell;				/* path to ispell and options */
1600 #endif /* HAVE_ISPELL */
1601 #ifdef CHARSET_CONVERSION
1602 	char *undeclared_charset;		/* charset of articles without MIME charset declaration */
1603 	int mm_network_charset;			/* network charset */
1604 #endif /* CHARSET_CONVERSION */
1605 	struct t_newsheader *headers_to_display;	/* array of which headers to display */
1606 	struct t_newsheader *headers_to_not_display;	/* array of which headers to not display */
1607 	unsigned global:1;			/* global/group specific */
1608 	unsigned quick_kill_header:3;	/* quick filter kill header */
1609 	unsigned quick_kill_expire:1;	/* quick filter kill limited/unlimited time */
1610 	unsigned quick_kill_case:1;		/* quick filter kill case sensitive? */
1611 	unsigned quick_select_header:3;	/* quick filter select header */
1612 	unsigned quick_select_expire:1;	/* quick filter select limited/unlimited time */
1613 	unsigned quick_select_case:1;	/* quick filter select case sensitive? */
1614 	unsigned add_posted_to_filter:1;	/* add posted articles to filter */
1615 	unsigned advertising:1;			/* add User-Agent: -header */
1616 	unsigned alternative_handling:1;	/* skip multipart/alternative parts */
1617 	unsigned ask_for_metamail:1;	/* ask before using MIME viewer */
1618 	unsigned auto_cc_bcc:2;			/* add your name to cc/bcc automatically */
1619 	unsigned auto_list_thread:1;	/* list thread when entering it using right arrow */
1620 	unsigned auto_select:1;			/* 0=show all unread, 1='X' just hot arts */
1621 	unsigned auto_save:1;			/* 0=none, 1=save */
1622 	unsigned batch_save:1;			/* 0=none, 1=save -S/mail -M */
1623 	unsigned delete_tmp_files:1;	/* 0=leave, 1=delete */
1624 	unsigned group_catchup_on_exit:1;	/* ask if read groups are to be marked read */
1625 	unsigned mail_8bit_header:1;	/* allow 8bit chars. in header of mail message */
1626 	unsigned mail_mime_encoding:2;
1627 	unsigned mark_ignore_tags:1;	/* Ignore tags for GROUP_MARK_THREAD_READ/THREAD_MARK_ARTICLE_READ */
1628 	unsigned mark_saved_read:1;		/* mark saved article/thread as read */
1629 	unsigned pos_first_unread:1;	/* position cursor at first/last unread article */
1630 	unsigned post_8bit_header:1;	/* allow 8bit chars. in header when posting to newsgroup */
1631 	unsigned post_mime_encoding:2;
1632 	unsigned post_process_view:1;	/* set TRUE to invoke mailcap viewer app */
1633 #ifndef DISABLE_PRINTING
1634 	unsigned print_header:1;		/* print all of mail header or just Subject: & From lines */
1635 #endif /* !DISABLE_PRINTING */
1636 	unsigned process_only_unread:1;	/* save/print//mail/pipe unread/all articles */
1637 	unsigned prompt_followupto:1;	/* display empty Followup-To header in editor */
1638 	unsigned show_only_unread_arts:1;	/* 0=all, 1=only unread */
1639 	unsigned sigdashes:1;			/* set TRUE to prepend every signature with dashes */
1640 	unsigned signature_repost:1;	/* set TRUE to add signature when reposting articles */
1641 	unsigned start_editor_offset:1;	/* start editor with line offset */
1642 	unsigned thread_articles:3;			/* 0=unthread, 1=subject, 2=refs, 3=both, 4=multipart, 5=percentage */
1643 	unsigned thread_catchup_on_exit:1;	/* catchup thread with left arrow key or not */
1644 	unsigned thread_perc:7;			/* percentage threading threshold */
1645 	unsigned show_author:2;			/* 0=none, 1=name, 2=addr, 3=both */
1646 	unsigned show_signatures:1;		/* 0=none, 1=show signatures */
1647 	unsigned trim_article_body:3;	/* 0=Don't trim article body, 1=Skip leading blank lines,
1648 						2=Skip trailing blank lines, 3=Skip leading and trailing blank lines,
1649 						4=Compact multiple blank lines between textblocks,
1650 						5=Compact multiple blank lines between textblocks and skip leading blank lines,
1651 						6=Compact multiple blank lines between textblocks and skip trailing blank lines,
1652 						7=Compact multiple blank lines between textblocks and skip leading and trailing
1653 						  blank lines */
1654 	unsigned verbatim_handling:1;	/* 0=none, 1=detect verbatim blocks */
1655 #ifdef HAVE_COLOR
1656 	unsigned extquote_handling:1;		/* 0=none, 1=detect quoted text from external sources */
1657 #endif /* HAVE_COLOR */
1658 	unsigned wrap_on_next_unread:1;	/* Wrap around threads when searching next unread article */
1659 	unsigned sort_article_type:4;		/* 0=none, 1=subj descend, 2=subj ascend,
1660 						   3=from descend, 4=from ascend,
1661 						   5=date descend, 6=date ascend,
1662 						   7=score descend, 8=score ascend */
1663 	unsigned sort_threads_type:3;	/* 0=none, 1=score descend, 2=score ascend,
1664 						   3=last posting date descend, 4=last posting date ascend */
1665 	unsigned post_process_type:2;	/* 0=none, 1=shar, 2=uudecode */
1666 	unsigned x_comment_to:1;	/* insert X-Comment-To: in Followup */
1667 	unsigned tex2iso_conv:1;	/* Convert TeX2ISO */
1668 	unsigned mime_forward:1;	/* forward articles as attachment or inline */
1669 };
1670 
1671 /*
1672  * struct t_attribute_state - holds additional information
1673  * about numeric attributes within a scope
1674  */
1675 struct t_attribute_state {
1676 	unsigned add_posted_to_filter:1;
1677 	unsigned advertising:1;
1678 	unsigned alternative_handling:1;
1679 	unsigned ask_for_metamail:1;
1680 	unsigned auto_cc_bcc:1;
1681 	unsigned auto_list_thread:1;
1682 	unsigned auto_save:1;
1683 	unsigned auto_select:1;
1684 	unsigned batch_save:1;
1685 	unsigned date_format:1;
1686 	unsigned delete_tmp_files:1;
1687 	unsigned editor_format:1;
1688 	unsigned fcc:1;
1689 	unsigned followup_to:1;
1690 	unsigned from:1;
1691 	unsigned group_catchup_on_exit:1;
1692 	unsigned group_format:1;
1693 #ifdef HAVE_ISPELL
1694 	unsigned ispell:1;
1695 #endif /* HAVE_ISPELL */
1696 	unsigned mail_8bit_header:1;
1697 	unsigned mail_mime_encoding:1;
1698 	unsigned maildir:1;
1699 	unsigned mailing_list:1;
1700 	unsigned mark_ignore_tags:1;
1701 	unsigned mark_saved_read:1;
1702 	unsigned mime_forward:1;
1703 	unsigned mime_types_to_save:1;
1704 	unsigned news_headers_to_display:1;
1705 	unsigned news_headers_to_not_display:1;
1706 	unsigned news_quote_format:1;
1707 	unsigned organization:1;
1708 	unsigned pos_first_unread:1;
1709 	unsigned post_8bit_header:1;
1710 	unsigned post_mime_encoding:1;
1711 	unsigned post_process_view:1;
1712 	unsigned post_process_type:1;
1713 #ifndef DISABLE_PRINTING
1714 	unsigned print_header:1;
1715 #endif /* !DISABLE_PRINTING */
1716 	unsigned process_only_unread:1;
1717 	unsigned prompt_followupto:1;
1718 	unsigned quick_kill_case:1;
1719 	unsigned quick_kill_expire:1;
1720 	unsigned quick_kill_header:1;
1721 	unsigned quick_kill_scope:1;
1722 	unsigned quick_select_case:1;
1723 	unsigned quick_select_expire:1;
1724 	unsigned quick_select_header:1;
1725 	unsigned quick_select_scope:1;
1726 	unsigned quote_chars:1;
1727 	unsigned savedir:1;
1728 	unsigned savefile:1;
1729 	unsigned show_author:1;
1730 	unsigned show_only_unread_arts:1;
1731 	unsigned show_signatures:1;
1732 	unsigned sigdashes:1;
1733 	unsigned sigfile:1;
1734 	unsigned signature_repost:1;
1735 	unsigned sort_article_type:1;
1736 	unsigned sort_threads_type:1;
1737 	unsigned start_editor_offset:1;
1738 	unsigned tex2iso_conv:1;
1739 	unsigned thread_articles:1;
1740 	unsigned thread_catchup_on_exit:1;
1741 	unsigned thread_format:1;
1742 	unsigned thread_perc:1;
1743 	unsigned trim_article_body:1;
1744 #ifdef CHARSET_CONVERSION
1745 	unsigned undeclared_charset:1;
1746 	unsigned mm_network_charset:1;
1747 #endif /* CHARSET_CONVERSION */
1748 	unsigned verbatim_handling:1;
1749 #ifdef HAVE_COLOR
1750 	unsigned extquote_handling:1;
1751 #endif /* HAVE_COLOR */
1752 	unsigned wrap_on_next_unread:1;
1753 	unsigned x_body:1;
1754 	unsigned x_comment_to:1;
1755 	unsigned x_headers:1;
1756 };
1757 
1758 /*
1759  * struct t_scope
1760  */
1761 struct t_scope {
1762 	char *scope;				/* scope for these group attributes */
1763 	struct t_attribute *attribute;	/* the attributes itself */
1764 	struct t_attribute_state *state;	/* additional information about numeric attributes */
1765 	unsigned global:1;			/* TRUE for scopes from global_attributes_file */
1766 };
1767 
1768 /*
1769  * struct t_newsrc - newsrc related info.
1770  */
1771 struct t_newsrc {
1772 	t_bool present:1;		/* update newsrc? */
1773 	t_artnum num_unread;		/* unread articles in group */
1774 	t_artnum xmax;			/* newsrc max */
1775 	t_artnum xmin;			/* newsrc min */
1776 	t_artnum xbitlen;			/* bitmap length (max-min+1) */
1777 	t_bitmap *xbitmap;	/* bitmap read/unread (max-min+1+7)/8 */
1778 };
1779 
1780 /*
1781  * struct t_group - newsgroup info from active file
1782  */
1783 struct t_group {
1784 	char *name;			/* newsgroup/mailbox name */
1785 	char *aliasedto;		/* =new.group in active file, NULL if not */
1786 	char *description;	/* text from NEWSLIBDIR/newsgroups file */
1787 	char *spooldir;		/* groups spool directory */
1788 	char moderated;		/* state of group moderation */
1789 	t_artnum count;		/* article number count */
1790 	t_artnum xmax;		/* max. article number */
1791 	t_artnum xmin;		/* min. article number */
1792 	unsigned int type:4;		/* grouptype - newsgroup/mailbox/savebox */
1793 	t_bool inrange:1;		/* TRUE if group selected via # range command */
1794 	t_bool read_during_session:1;	/* TRUE if group entered during session */
1795 	t_bool art_was_posted:1;	/* TRUE if art was posted to group */
1796 	t_bool subscribed:1;		/* TRUE if subscribed to group */
1797 	t_bool newgroup:1;		/* TRUE if group was new this session */
1798 	t_bool bogus:1;			/* TRUE if group is not in active list */
1799 	int next;			/* next active entry in hash chain */
1800 	struct t_newsrc newsrc;		/* newsrc bitmap specific info. */
1801 	struct t_attribute *attribute;	/* group specific attributes */
1802 	struct t_filters *glob_filter;	/* points to filter array */
1803 };
1804 
1805 /*
1806  * used in hashstr.c
1807  */
1808 struct t_hashnode {
1809 	struct t_hashnode *next;	/* chain for spillover */
1810 	int aptr;			/* used in subject threading */
1811 	char txt[1];			/* stub for the string data, \0 terminated */
1812 };
1813 
1814 /*
1815  * used for variable screen layout
1816  *
1817  * holds a preparsed format string, a date format string and some
1818  * precalculated length
1819  */
1820 struct t_fmt {
1821 	char str[LEN];
1822 	char date_str[LEN];
1823 	size_t len_date;		/* %D Date */
1824 	size_t len_date_max;
1825 	size_t len_grpdesc;		/* %d newsgroup description */
1826 	size_t len_from;		/* %F From */
1827 	size_t len_grpname;		/* %G groupname */
1828 	size_t len_grpname_dsc;
1829 	size_t len_grpname_max;
1830 	size_t len_initials;	/* %I initials */
1831 	size_t len_linenumber;	/* %n linenumber on screen */
1832 	size_t len_linecnt;		/* %L line count (article) */
1833 	size_t len_msgid;		/* %M message-id */
1834 	size_t len_respcnt;		/* %R count, number of responses */
1835 	size_t len_score;		/* %S score */
1836 	size_t len_subj;		/* %s subject */
1837 	size_t len_ucnt;		/* %U unread count */
1838 	size_t flags_offset;
1839 	size_t mark_offset;
1840 	size_t ucnt_offset;
1841 	t_bool show_grpdesc;
1842 	t_bool d_before_f;
1843 	t_bool g_before_f;
1844 	t_bool d_before_u;
1845 	t_bool g_before_u;
1846 };
1847 
1848 /*
1849  * used in filter.c
1850  *
1851  * Create 2 filter arrays - global & local. Local will be part of group_t
1852  * structure and will have priority over global filter. Should help to
1853  * speed kill/selecting within a group. The long value number that is in
1854  * ~/.tin/kill will be replaced by group name so that it is more human
1855  * readable and that if hash routine is changed it will still work.
1856  *
1857  * Add time period to filter_t struct to allow timed kills & auto-selection
1858  * Default kill & select time 28 days. Store as a long and compare when
1859  * loading against present time. If time secs is passed set flag to save
1860  * filter file and don't load expired entry. Renamed to filter because of
1861  * future directions in adding other retrieval methods to present kill &
1862  * auto selection.
1863  *
1864  * Also separate kill/select screen to allow ^K=kill ^A=auto-select
1865  */
1866 struct t_filters {
1867 	int max;
1868 	int num;
1869 	struct t_filter *filter;
1870 };
1871 
1872 /*
1873  * struct t_filter_comment: allow multiple comment-lines in filter-file.
1874  */
1875 struct t_filter_comment {
1876 	char *text;			/* One line of comment. */
1877 	struct t_filter_comment *next;	/* points to next comment-entry */
1878 };
1879 
1880 /*
1881  * struct t_filter - local & global filtering (ie. kill & auto-selection)
1882  */
1883 struct t_filter {
1884 	struct t_filter_comment *comment;
1885 	char *scope;			/* NULL='*' (all groups) or 'comp.os.*' */
1886 	char *subj;			/* Subject: line */
1887 	char *from;			/* From: line */
1888 	char *msgid;			/* Message-ID: line */
1889 	char lines_cmp;			/* Lines compare <> */
1890 	int lines_num;			/* Lines: line */
1891 	char gnksa_cmp;			/* GNKSA compare <> */
1892 	int gnksa_num;			/* GNKSA code */
1893 	int score;			/* score to give if rule matches */
1894 	char *xref;			/* groups in xref line */
1895 	char *path;			/* server in path line */
1896 	time_t time;			/* expire time in seconds */
1897 	struct t_filter *next;		/* next rule valid in group */
1898 	unsigned int inscope:4;		/* if group matches scope e.g. 'comp.os.*' */
1899 	unsigned int icase:2;		/* Case sensitive filtering */
1900 	unsigned int fullref:4;		/* use full references or last entry only */
1901 };
1902 
1903 /*
1904  * struct t_filter_rule - provides parameters to build filter rule from
1905  */
1906 struct t_filter_rule {
1907 	struct t_filter_comment *comment;
1908 	char text[PATH_LEN];
1909 	char scope[PATH_LEN];
1910 	int counter;
1911 	int icase;
1912 	int fullref;
1913 	int lines_cmp;
1914 	int lines_num;
1915 	int score;
1916 	int expire_time;
1917 	t_bool from_ok:1;
1918 	t_bool lines_ok:1;
1919 	t_bool msgid_ok:1;
1920 	t_bool subj_ok:1;
1921 	t_bool check_string:1;
1922 };
1923 
1924 /*
1925  * Filter cache structure using Philip Hazel's Perl regular expression
1926  * library (see pcre/pcre.[ch] for details)
1927  */
1928 struct regex_cache {
1929 	pcre *re;
1930 	pcre_extra *extra;
1931 };
1932 
1933 struct t_save {
1934 	char *path;
1935 	char *file;					/* ptr to file part of *path */
1936 	t_bool mailbox:1;			/* Set if path is a mailbox */
1937 };
1938 
1939 #ifndef USE_CURSES
1940 struct t_screen {
1941 	char *col;
1942 };
1943 #endif /* !USE_CURSES */
1944 
1945 struct t_posted {
1946 	char date[10];
1947 	char group[80];
1948 	char action;
1949 	char subj[120];
1950 };
1951 
1952 struct t_art_stat {
1953 	char art_mark;		/* mark to use for this thread - not used for groups */
1954 	int total;		/* total article count */
1955 	int unread;		/* number of unread articles (does not include seen) arts */
1956 	int seen;		/* number of seen articles (ART_WILL_RETURN) */
1957 	int deleted;		/* number of articles marked for deletion (mailgroups) */
1958 	int inrange;		/* number of articles marked in a range */
1959 	int selected_total;	/* total selected count */
1960 	int selected_unread;	/* selected and unread */
1961 	int selected_seen;	/* selected and seen */
1962 	int killed;		/* killed */
1963 	int score;		/* maximum score */
1964 	int multipart_total; /* 0=not multipart, >0 = number of articles in the multipart */
1965 	int multipart_have; /* number of articles we actually have found */
1966 	int multipart_compare_len; /* length of subject which contains non-specific multipart info */
1967 	time_t time;		/* latest time */
1968 };
1969 
1970 
1971 /*
1972  * Used for detecting changes in active file size on different news servers
1973  */
1974 struct t_newnews {
1975 	char *host;
1976 	time_t time;
1977 };
1978 
1979 typedef const char constext;
1980 
1981 /*
1982  * Defines text strings used by a tinrc variable
1983  */
1984 struct opttxt {
1985 	constext *help;					/* Helptext on Option Menu */
1986 	constext *opt;					/* Text on body of Option Menu screen */
1987 	constext *tinrc;				/* (optional) Text written with variable to tinrc file */
1988 };
1989 
1990 /*
1991  * Used for building option menu
1992  */
1993 struct t_option {
1994 	int var_type;		/* type of variable (see tincfg.h) */
1995 	int var_index;		/* index in corresponding table */
1996 	int *variable;		/* ptr to variable to change */
1997 	constext **opt_list;	/* ptr to list entries if OPT_LIST */
1998 	struct opttxt *txt;	/* ptr to information/help on option */
1999 };
2000 
2001 /*
2002  * Multipart article detection
2003  */
2004 typedef struct {
2005 	char *subject;
2006 	int subject_compare_len;
2007 	int part_number;
2008 	int total;
2009 	int arts_index;
2010 } MultiPartInfo;
2011 
2012 
2013 /*
2014  * Key information about current menu screen
2015  */
2016 typedef struct {
2017 	int curr;					/* Current cursor pos (cur_groupnum, index_point, thread_index_point) */
2018 	int max;					/* Max # on current menu (group_top, top_base, top_thread) */
2019 	int first;					/* First # on current menu */
2020 	void (*redraw) (void);		/* Redraw function */
2021 	void (*draw_arrow) (void);	/* Arrow draw */
2022 	void (*draw_item) (int item);	/* draw the specified item */
2023 } t_menu;
2024 
2025 
2026 /*
2027  * Packet of data needed to enter pager
2028  */
2029 typedef struct {
2030 	int art;
2031 	t_bool ignore_unavail:1;
2032 } t_pagerinfo;
2033 
2034 
2035 /*
2036  * Time functions.
2037  */
2038 typedef struct _TIMEINFO {
2039 	time_t time;
2040 	long usec;
2041 	long tzone;
2042 } TIMEINFO;
2043 
2044 
2045 struct t_tintime {
2046 	time_t tv_sec; /* seconds */
2047 	long tv_nsec; /* nanoseconds */
2048 };
2049 
2050 
2051 /*
2052  * mailcap fields
2053  * the x-token field is missing, we would need something like
2054  * struct t_xtoken { char *xtoken; t_xtoken *next; } for that ...
2055  */
2056 typedef struct {
2057 	char *type;		/* content-type, mandatory */
2058 	char *command;	/* view-command, mandatory */
2059 	char *compose;
2060 	char *composetyped;
2061 	char *description;
2062 	char *edit;
2063 	char *nametemplate;
2064 	char *print;
2065 	char *test;
2066 	char *x11bitmap;
2067 	int textualnewlines;
2068 	t_bool needsterminal:1;
2069 	t_bool copiousoutput:1;
2070 } t_mailcap;
2071 
2072 
2073 typedef struct urllist {
2074 	char *url;
2075 	struct urllist *next;
2076 } t_url;
2077 
2078 
2079 /*
2080  * Determine signal return type
2081  */
2082 #ifndef RETSIGTYPE
2083 #	define RETSIGTYPE void
2084 #endif /* !RETSIGTYPE */
2085 
2086 /*
2087  * Determine qsort compare type
2088  */
2089 #ifdef HAVE_COMPTYPE_VOID
2090 #	ifdef __STDC__
2091 		typedef const void *t_comptype;
2092 #	else
2093 		typedef void *t_comptype;
2094 #	endif /* __STDC__ */
2095 #else
2096 #	ifdef HAVE_COMPTYPE_CHAR
2097 		typedef char *t_comptype;
2098 #	endif /* HAVE_COMPTYPE_CHAR */
2099 #endif /* HAVE_COMPTYPE_VOID */
2100 
2101 /* Define a matching function pointer type */
2102 typedef int (*t_compfunc)(t_comptype, t_comptype);
2103 typedef void (*t_sortfunc)(void *, size_t, size_t, t_compfunc);
2104 
2105 #define _CDECL
2106 
2107 /* set to (void)heapsort or qsort */
2108 #ifndef USE_HEAPSORT
2109 #	define tin_sort qsort
2110 #else
2111 #	define MAX_SORT_FUNCS 1
2112 #endif /* !USE_HEAPSORT */
2113 
2114 /* Separator between dir part of path & the filename */
2115 #define DIRSEP	'/'
2116 
2117 /*
2118  * mouse buttons for use in xterm
2119  */
2120 #define MOUSE_BUTTON_1		0
2121 #define MOUSE_BUTTON_2		1
2122 #define MOUSE_BUTTON_3		2
2123 
2124 
2125 #define REDIRECT_OUTPUT		"> /dev/null 2>&1"
2126 #define REDIRECT_PGP_OUTPUT		"> /dev/null"
2127 #define ENV_VAR_MAILER		"MAILER"
2128 #define ENV_VAR_SHELL		"SHELL"
2129 #define TIN_EDITOR_FMT_OFF		"%E %F"
2130 #define TIN_EDITOR_FMT_ON		"%E +%N %F"
2131 #define MAILER_FORMAT		"%M -oi -t < %F"
2132 #define TMPDIR	get_val("TMPDIR", _PATH_TMP)
2133 #ifdef HAVE_KEY_PREFIX
2134 #	define KEY_PREFIX		0x8f: case 0x9b
2135 #endif /* HAVE_KEY_PREFIX */
2136 
2137 #if !defined(S_ISDIR)
2138 #	define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
2139 #endif /* !S_ISDIR */
2140 
2141 #if !defined(S_ISREG)
2142 #	define S_ISREG(m)	(((m) & S_IFMT) == S_IFREG)
2143 #endif /* !S_ISREG */
2144 
2145 #ifndef S_IRWXU /* should be defined in <sys/stat.h> */
2146 #	define S_IRWXU	0000700	/* read, write, execute permission (owner) */
2147 #	define S_IRUSR	0000400	/* read permission (owner) */
2148 #	define S_IWUSR	0000200	/* write permission (owner) */
2149 #	define S_IXUSR	0000100	/* execute permission (owner) */
2150 
2151 #	define S_IRWXG	0000070	/* read, write, execute permission (group) */
2152 #	define S_IRGRP	0000040	/* read permission (group) */
2153 #	define S_IWGRP	0000020	/* write permission (group) */
2154 #	define S_IXGRP	0000010	/* execute permission (group) */
2155 
2156 #	define S_IRWXO	0000007	/* read, write, execute permission (other) */
2157 #	define S_IROTH	0000004	/* read permission (other) */
2158 #	define S_IWOTH	0000002	/* write permission (other) */
2159 #	define S_IXOTH	0000001	/* execute permission (other) */
2160 #endif /* !S_IRWXU */
2161 
2162 /* the next two are needed for fcc 1.0 on linux */
2163 #ifndef S_IFMT
2164 #	define S_IFMT	0xF000	/* type of file */
2165 #endif /* S_IFMT */
2166 #ifndef S_IFREG
2167 #	define S_IFREG	0x8000	/* regular */
2168 #endif /* S_IFREG */
2169 
2170 #ifndef S_IRWXUGO
2171 #	define S_IRWXUGO	(S_IRWXU|S_IRWXG|S_IRWXO)	/* read, write, execute permission (all) */
2172 #	define S_IRUGO	(S_IRUSR|S_IRGRP|S_IROTH)	/* read permission (all) */
2173 #	define S_IWUGO	(S_IWUSR|S_IWGRP|S_IWOTH)	/* write permission (all) */
2174 #	define S_IXUGO	(S_IXUSR|S_IXGRP|S_IXOTH)	/* execute permission (all) */
2175 #endif /* !S_IRWXUGO */
2176 
2177 #ifndef S_ISVTX
2178 #	define S_ISVTX 0
2179 #endif /* !S_ISVTX */
2180 
2181 #ifdef DONT_HAVE_PIPING
2182 #	define TIN_PRINTFILE "tinprint%d.tmp"
2183 #endif /* DONT_HAVE_PIPING */
2184 
2185 /*
2186  * Defines for access()
2187  */
2188 #ifndef R_OK
2189 #	define R_OK	4	/* Test for Read permission */
2190 #endif /* !R_OK */
2191 #ifndef W_OK
2192 #	define W_OK	2	/* Test for Write permission */
2193 #endif /* !W_OK */
2194 #ifndef X_OK
2195 #	define X_OK	1	/* Test for eXecute permission */
2196 #endif /* !X_OK */
2197 #ifndef F_OK
2198 #	define F_OK	0	/* Test for existence of File */
2199 #endif /* !F_OK */
2200 
2201 /* Various function redefinitions */
2202 #if defined(USE_DBMALLOC) || defined(USE_DMALLOC)
2203 #	define my_malloc(size)	malloc(size)
2204 #	define my_calloc(nmemb, size)	calloc((nmemb), (size))
2205 #	define my_realloc(ptr, size)	realloc((ptr), (size))
2206 #else
2207 #	define my_malloc(size)	my_malloc1(__FILE__, __LINE__, (size))
2208 #	define my_calloc(nmemb, size)	my_calloc1(__FILE__, __LINE__, (nmemb), (size))
2209 #	define my_realloc(ptr, size)	my_realloc1(__FILE__, __LINE__, (ptr), (size))
2210 #endif /* USE_DBMALLOC || USE_DMALLOC */
2211 
2212 #define ARRAY_SIZE(array)	((int) (sizeof(array) / sizeof(array[0])))
2213 
2214 #define FreeIfNeeded(p)	if (p != NULL) free((void *) p)
2215 #define FreeAndNull(p)	if (p != NULL) { free((void *) p); p = NULL; }
2216 
2217 #define BlankIfNull(p)	((p) ? (p) : "")
2218 
2219 #define my_group_find(x)	add_my_group(x, FALSE, FALSE)
2220 #define my_group_add(x, y)		add_my_group(x, TRUE, y)
2221 #define for_each_group(x)	for (x = 0; x < num_active; x++)
2222 #define for_each_art(x)		for (x = 0; x < top_art; x++)
2223 #define for_each_art_in_thread(x, y)	for (x = (int) base[y]; x >= 0; x = arts[x].thread)
2224 
2225 /*
2226  * Cast for the (few!) places where we need to examine 8-bit characters w/o
2227  * sign-extension, and a corresponding test-macro.
2228  */
2229 #define EIGHT_BIT(ptr)	(unsigned char *)ptr
2230 #define is_EIGHT_BIT(p)	((*EIGHT_BIT(p) < 32 && !isspace((int)*p)) || *EIGHT_BIT(p) > 127)
2231 
2232 /*
2233  * function prototypes & extern definitions
2234  */
2235 
2236 #ifndef SIG_ARGS
2237 #	if defined(__STDC__)
2238 #		define SIG_ARGS	int sig
2239 #	endif /* __STDC__ */
2240 #endif /* !SIG_ARGS */
2241 
2242 #ifndef __LCLINT__ /* lclint doesn't like it */
2243 /* stifle complaints about not-a-prototype from gcc */
2244 #	ifdef DECL_SIG_CONST
2245 #		undef	SIG_DFL
2246 #		define SIG_DFL	(void (*)(SIG_ARGS))0
2247 #		undef	SIG_IGN
2248 #		define SIG_IGN	(void (*)(SIG_ARGS))1
2249 #		undef	SIG_ERR
2250 #		define SIG_ERR	(void (*)(SIG_ARGS))-1
2251 #	endif /* DECL_SIG_CONST */
2252 #endif /* !__LCLINT__ */
2253 
2254 /*
2255  * tputs() function-param
2256  */
2257 #ifdef OUTC_RETURN
2258 #	define OUTC_RETTYPE	int
2259 #else
2260 #	define OUTC_RETTYPE	void
2261 #endif /* OUTC_RETURN */
2262 
2263 #ifndef OUTC_ARGS
2264 #	define OUTC_ARGS	int c
2265 #endif /* !OUTC_ARGS */
2266 
2267 #if __STDC__ || defined(__cplusplus)
2268 #	define OUTC_FUNCTION(func)	OUTC_RETTYPE func (OUTC_ARGS)
2269 #else
2270 #	define OUTC_FUNCTION(func)	OUTC_RETTYPE func (c) int c;
2271 #endif /* __STDC__ || __cplusplus */
2272 
2273 typedef OUTC_RETTYPE (*OutcPtr) (OUTC_ARGS);
2274 typedef FILE TCP;
2275 
2276 #ifndef EXTERN_H
2277 #	include "extern.h"
2278 #endif /* !EXTERN_H */
2279 #ifndef TINRC_H
2280 #	include "tinrc.h"
2281 #endif /* !TINRC_H */
2282 #ifndef NNTPLIB_H
2283 #	include "nntplib.h"
2284 #endif /* !NNTPLIB_H */
2285 
2286 #ifndef __CPROTO__
2287 #	ifndef PROTO_H
2288 #		include "proto.h"
2289 #	endif /* !PROTO_H */
2290 #endif /* !__CPROTO__ */
2291 
2292 /*
2293  * rfc1521/rfc1522 interface
2294  */
2295 typedef void (*BodyPtr) (char *, FILE *, int);
2296 
2297 #ifdef USE_DBMALLOC
2298 #	undef strchr
2299 #	undef strrchr
2300 #	include <dbmalloc.h> /* dbmalloc 1.4 */
2301 #endif /* USE_DBMALLOC */
2302 
2303 #ifdef USE_DMALLOC
2304 #	include <dmalloc.h>
2305 #	define DMALLOC_FUNC_CHECK
2306 #	ifdef HAVE_STRDUP
2307 #		define my_strdup(s) strdup((s))
2308 #	endif /* HAVE_STRDUP */
2309 #endif /* USE_DMALLOC */
2310 
2311 #ifdef DOALLOC
2312 	extern char *doalloc(char *, size_t);
2313 	extern char *docalloc(size_t, size_t);
2314 	extern void	dofree(char *);
2315 #	undef malloc
2316 #	undef realloc
2317 #	undef calloc
2318 #	undef free
2319 #	define malloc(n)	doalloc((char *) 0, n)
2320 #	define realloc		doalloc
2321 #	define calloc		docalloc
2322 #	define free		dofree
2323 	extern void	fail_alloc(char *, char *);
2324 	extern void	Trace(char *, ...);
2325 	extern void	Elapsed(char *);
2326 	extern void	WalkBack(void);
2327 	extern void	show_alloc(void);
2328 	extern void	no_leaks(void);
2329 #endif /* DOALLOC */
2330 
2331 /* define some standard places to look for a tin.defaults file */
2332 #define TIN_DEFAULTS_BUILTIN "/etc/opt/tin","/etc/tin","/etc","/usr/local/lib/tin","/usr/local/lib","/usr/local/etc/tin","/usr/local/etc","/usr/lib/tin","/usr/lib",NULL
2333 #ifdef TIN_DEFAULTS_DIR
2334 #	define TIN_DEFAULTS TIN_DEFAULTS_DIR,TIN_DEFAULTS_BUILTIN
2335 #else
2336 #	define TIN_DEFAULTS TIN_DEFAULTS_BUILTIN
2337 #endif /* TIN_DEFAULTS_DIR */
2338 
2339 /*
2340  * We force this include-ordering since socks.h contains redefinitions of
2341  * functions that probably are prototyped via other includes. The socks.h
2342  * definitions have to be included everywhere, since they're making wrappers
2343  * for the stdio functions as well as the network functions.
2344  */
2345 #ifdef USE_SOCKS5
2346 #	define SOCKS
2347 #	include <socks.h>
2348 /* socks.h doesn't define prototypes for use */
2349 extern size_t read(int, char *, size_t);
2350 extern int dup(int);
2351 extern int close(int);
2352 extern int fprintf(FILE *, const char *, ...);
2353 extern int fclose(FILE *);
2354 extern struct tm *localtime(time_t *);
2355 #endif /* USE_SOCKS5 */
2356 
2357 #ifdef SETVBUF_REVERSED
2358 #	define SETVBUF(stream, buf, mode, size)	setvbuf(stream, mode, buf, size)
2359 #else
2360 #	define SETVBUF(stream, buf, mode, size)	setvbuf(stream, buf, mode, size)
2361 #endif /* SETVBUF_REVERSED */
2362 
2363 #ifdef CLOSEDIR_VOID
2364 #	define CLOSEDIR(DIR)	closedir(DIR)
2365 #else
2366 #	define CLOSEDIR(DIR)	if (closedir(DIR)) error_message(2, "closedir() failed: %s %d", __FILE__, __LINE__)
2367 #endif /* CLOSEDIR_VOID */
2368 
2369 #ifdef HAVE_GETTIMEOFDAY
2370 #	ifndef GETTIMEOFDAY_2ARGS
2371 #		define gettimeofday(a,b) gettimeofday(a)
2372 #	endif /* GETTIMEOFDAY_2ARGS */
2373 #endif /* HAVE_GETTIMEOFDAY */
2374 
2375 /* libmss */
2376 #ifdef MSS
2377 #	ifdef strdup
2378 #		undef strdup
2379 #	endif /* strdup */
2380 #	include <mss.h>
2381 #	undef my_malloc
2382 #	undef my_realloc
2383 #	undef my_calloc
2384 #	define my_malloc(size)	malloc(size)
2385 #	define my_realloc(ptr, size)	realloc((ptr), (size))
2386 #	define my_calloc(nmemb, size) calloc((nmemb), (size))
2387 #endif /* MSS */
2388 
2389 /* libcanlock */
2390 #ifdef USE_CANLOCK
2391 #	ifdef HAVE_LIBCANLOCK_3_CANLOCK_H
2392 #		include <libcanlock-3/canlock.h>
2393 #	else
2394 #		include <canlock.h>
2395 #	endif /* HAVE_LIBCANLOCK_3_CANLOCK_H */
2396 #endif /* USE_CANLOCK */
2397 
2398 /* gsasl */
2399 #ifdef USE_SASL
2400 #	include <gsasl.h>
2401 #endif /* USE_SASL */
2402 
2403 /*
2404  * adapted from ncurses curses.priv.h:
2405  * If we have va_copy(), use it for assigning va_list's.
2406  */
2407 #if defined(HAVE___VA_COPY)
2408 #	define begin_va_copy(dst,src)	__va_copy(dst, src)
2409 #	define end_va_copy(dst)	va_end(dst)
2410 #else
2411 #	if defined(va_copy) || defined(HAVE_VA_COPY)
2412 #		define begin_va_copy(dst,src)	va_copy(dst, src)
2413 #		define end_va_copy(dst)	va_end(dst)
2414 #	else
2415 #		if defined(HAVE___BUILTIN_VA_COPY)
2416 #			define begin_va_copy(dst,src)	__builtin_va_copy(dst, src)
2417 #			define end_va_copy(dst)	va_end(dst)
2418 #		else
2419 #			if defined(ARRAY_VA_LIST)
2420 #				define begin_va_copy(dst,src)	*(dst) = *(src)
2421 #				define end_va_copy(dst)	/* nothing */
2422 #			else
2423 #				define begin_va_copy(dst,src)	(dst) = (src)
2424 #				define end_va_copy(dst)	/* nothing */
2425 #			endif /* ARRAY_VA_LIST */
2426 #		endif /* HAVE___BUILTIN_VA_COPY */
2427 #	endif /* va_copy || HAVE_VA_COPY */
2428 #endif /* HAVE___VA_COPY */
2429 
2430 /* snprintf(), vsnprintf() */
2431 #ifndef HAVE_SNPRINTF
2432 #	define snprintf	plp_snprintf
2433 #endif /* HAVE_SNPRINTF */
2434 #ifndef HAVE_VSNPRINTF
2435 #	define vsnprintf	plp_vsnprintf
2436 #endif /* HAVE_VSNPRINTF */
2437 
2438 /* gcc-specific attributes */
2439 #if defined(__GNUC__) && !defined(__cplusplus) && !defined(__APPLE_CC__) && !defined(__NeXT__)
2440 #	if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
2441 #		define UNUSED(x) x __attribute__((unused))
2442 #	else
2443 #		define UNUSED(x) x
2444 #	endif /*  __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6) */
2445 #else
2446 #	define UNUSED(x) x
2447 #endif /* __GNUC__ && !__cplusplus && !__APPLE_CC__ && !__NeXT__ */
2448 
2449 /* init_selfinfo() needs MM_CHARSET */
2450 #ifndef MM_CHARSET
2451 #	define MM_CHARSET "US-ASCII"
2452 #endif /* !MM_CHARSET */
2453 
2454 
2455 #if !defined(SEEK_SET)
2456 #	define SEEK_SET 0L
2457 #endif /* !SEEK_SET */
2458 
2459 #if !defined(EOF)
2460 #	define EOF -1
2461 #endif /* !EOF */
2462 
2463 /* various filenames used by tin */
2464 #define TIN_ARTICLE_NAME	".article"
2465 #define TIN_CANCEL_NAME	".cancel"
2466 #define TIN_LETTER_NAME	".letter"
2467 #define TIN_BUGREPORT_NAME	".bugreport"
2468 
2469 /* read_news_active_file() / open_newsgroups_fp() */
2470 #ifndef DISABLE_PIPELINING
2471 #	define PIPELINE_LIMIT 45
2472 #else
2473 #	define PIPELINE_LIMIT 1
2474 #endif /* DISABLE_PIPELINING */
2475 
2476 #ifndef DEBUG_H
2477 #	include "debug.h"
2478 #endif /* !DEBUG_H */
2479 
2480 struct t_overview_fmt {
2481 	char *name;
2482 	enum f_type type;
2483 };
2484 
2485 struct t_version {
2486 	enum rc_state state;
2487 	int file_version;		/* rc_majorv * 10000 + rc_minorv * 100 + rc_subv */
2488 /*	int current_version;*/	/* c_majorv * 10000 + c_minorv * 100 + c_subv */
2489 };
2490 
2491 #endif /* !TIN_H */
2492