project('fetchmail', 'c', 
  version: '6.6.7', # align with fetchmail.man - and don't remove, configure.ac greps for this!
  default_options : ['warning_level=2',
                     'c_std=gnu99'],
  meson_version : '>=1.3.0')

cc = meson.get_compiler('c')
cdata = configuration_data()

fs = import('fs')

if fs.exists('config.status')
  error('source directory configured with autoconf\'s configure, run \'make distclean\' there first')
endif

cmd = run_command('sh', '-c', 'echo $SOURCE_DATE_EPOCH', check:true)
source_date_epoch = cmd.stdout().strip()
myenv = environment()
if source_date_epoch != ''
	myenv.set('SOURCE_DATE_EPOCH', source_date_epoch)
endif

common_arguments = []
c_arguments = []
# cpp_arguments = []

if cc.get_id() == 'clang' or cc.get_id() == 'gcc'
  if get_option('optimization') != '0'
    common_arguments += [ '-D_FORTIFY_SOURCE=3' ]
  endif
endif

c_arguments += common_arguments
# cpp_arguments += common_arguments

add_project_arguments(c_arguments, '-DHAVE_CONFIG_H', language: 'c')
add_project_link_arguments(c_arguments, language: 'c')
#add_project_arguments(cpp_arguments, language: 'cpp')
#add_project_link_arguments(cpp_arguments, language: 'cpp')

link_deps = []

# GSSAPI options, MIT and Heimdal
use_gssapi = get_option('krb5-gssapi')
if use_gssapi.disabled()
  gssapi = disabler()
else
  gssapi = dependency('krb5-gssapi', required: false)
  if not gssapi.found()
    krb5_config = find_program('krb5-config', disabler: true, required: false)
    if krb5_config.found()
      message('Falling back to ' + krb5_config.full_path())
      gssapi_cflags = run_command(krb5_config, '--cflags', 'gssapi', capture: true, check: true).stdout().strip().split()
      gssapi_libs   = run_command(krb5_config, '--libs',   'gssapi', capture: true, check: true).stdout().strip().split()
      gssapi = declare_dependency(compile_args: gssapi_cflags, link_args: gssapi_libs)
    endif
  endif
endif
if use_gssapi.enabled() and not gssapi.found()
  error('krb5-gssapi enabled but not found')
endif

if gssapi.found() and not use_gssapi.disabled()
  cdata.set('GSSAPI', 1)
  link_deps += gssapi
endif

if host_machine.system() == 'openbsd'
  openssl_min_ver='>=1.0.0'
else
  openssl_min_ver='>=3.0.9'
endif

tls_lib_opt = get_option('tls_library')

if tls_lib_opt == 'openssl'
  tls_library_dep = dependency('OpenSSL', version: openssl_min_ver)
elif tls_lib_opt == 'aws-lc'
  tls_library_dep = dependency('aws-lc', version: '>=1.1.1')  # this is the OpenSSL compat version claimed
  aws_lc_needed = '>=1.71.0'
  # now get real AWS-LC version number and check
  realver = cc.get_define('AWSLC_VERSION_NUMBER_STRING',
    prefix: '#include <openssl/base.h>',
    dependencies: tls_library_dep)
  aws_lc_sufficient = realver.version_compare(aws_lc_needed)
  if not aws_lc_sufficient
    error('Your AWS-LC version', realver, 'is too old, need', aws_lc_needed)
  endif
elif tls_lib_opt == 'wolfssl'
  tls_library_dep = dependency('wolfssl', version: '>=5.7.2')
  # ensure we put wolfssl early in the include path so we find
  # its headers before finding OpenSSL's on systems that have both installed
  # since we want to use wolfSSL's OpenSSL header.
  if tls_library_dep.type_name() == 'cmake'
    warning('The wolfssl library path is guessed from internal variables that worked with 5.9.1\'s lib/cmake/wolfssl/wolfssl-targets.cmake - if it fails, try adding --pkg-config-path to <wolfssl-prefix>/lib/pkgconfig')
  endif
  add_project_arguments('-DWOLFSSL_USE_OPTIONS_H=1',
    '-I' + tls_library_dep.get_variable('includedir', cmake: '_wolfssl_includedir') + '/wolfssl',
    language: 'c')
  trustfile = get_option('WOLFSSL_TRUST_FILE')
  if trustfile == '' or not fs.exists(trustfile)
    error('WOLFSSL_TRUST_FILE = "' + trustfile + '" does not exist. Add -DWOLFSSL_TRUST_FILE=/path/to/cert.pem (adjust as needed) and re-run meson.')
  else
    message('Defaulting trust anchor to certificate bundle "' + trustfile + '"')
  endif
  add_project_arguments('-DWOLFSSL_TRUST_FILE="' + trustfile + '"', language: 'c')
endif
link_deps += tls_library_dep

if host_machine.system() == 'sunos'
  # OpenIndiana needs these two
  libnsl = cc.find_library('nsl')
  libsocket = cc.find_library('socket')
  link_deps += [libsocket, libnsl]
endif

resolv_library = dependency('resolv', required: false)
link_deps += resolv_library

intl_library = dependency('intl', required: false)
link_deps += intl_library

# localisation (l10n) and internationalization (i18n)
subdir('po')

# cmake_cxx_standard = '14'
fetchmail_sources = ['base64.c', 'checkalias.c', 'conf.c', 'cram.c', 'daemon.c', 'driver.c', 'env.c', 'etrn.c', 'lib/explicit_bzero.c', 'fetchmail.c', 'fetchmail.h', 'fm_getaddrinfo.c', 'fm_md5.h', 'fm_realpath.c', 'fm_strl.h', 'getpass.c', 'gettext.h', 'gssapi.c', 'i18n.h', 'idle.c', 'idlist.c', 'imap.c', 'interface.c', 'kerberos.c', 'kerberos.h', 'lock.c', 'lock.h', 'md5c.c', 'md5ify.c', 'mx.h', 'mxget.c', 'netrc.c', 'netrc.h', 'ntlm.h', 'ntlmsubr.c', 'odmr.c', 'opie.c', 'options.c', 'pop2.c', 'pop3.c', 'report.c', 'rfc2047e.c', 'regex_helper.c', 'rfc822.c', 'rfc822valid.c', 'rpa.c', 'sdump.c', 'sdump.h', 'servport.c', 'sink.c', 'smbbyteorder.h', 'smbdes.c', 'smbdes.h', 'smbencrypt.c', 'smbencrypt.h', 'smbmd4.c', 'smbmd4.h', 'smbtypes.h', 'smbutil.c', 'smtp.c', 'smtp.h', 'socket.c', 'socket.h', 'starttls.c', 'lib/stpcpy.c', 'lib/strlcat.c', 'lib/strlcpy.c', 'tls-aux.c', 'tls-aux.h', 'transact.c', 'tunable.h', 'uid.c', 'uid_db.c', 'uid_db.h', 'unmime.c', 'x509_name_match.c', 'xmalloc.c', 'xmalloc.h', 'ucs/norm_charmap.h', 'ucs/norm_charmap.c']

# code to determine if we're an end-user tarball build, or a maintainer build:
# the meson-dist-script.sh will add a tarball marker, and only if that is existing,
# we allow skipping maintainer tools.
if fs.exists('fetchmail.tarball')
  need_maint_tools = false
  message('Running from a fetchmail release distribution, allowing to skip maintainer tools')
else
  need_maint_tools = true
  message('Running outside distribution, requiring maintainer tools')
endif

flex = find_program('flex', required: need_maint_tools)
bison = find_program('bison', required: need_maint_tools)

if flex.found()
lexer = custom_target('scanner',
  output: ['rcfile_l.c', 'rcfile_l.h'],
  input:  'rcfile_l.l',
  command: [flex, '-o', '@OUTPUT0@', '@INPUT@'])
else
  lexer = 'rcfile_l.c'
endif

if bison.found()
parser = custom_target('parser',
  output: ['rcfile_y.c', 'rcfile_y.h'],
  input:  'rcfile_y.y',
  command: [bison, '-d', '-t', '@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@'],
)
else
  parser = 'rcfile_y.c'
endif

# Python for fetchmailconf
pymod = import('python')
pyinst = pymod.find_installation('python3', required: false) # XXX TODO FIXME: if we have meson, we have python... so rather disable the outputs
if pyinst.found()
  cdata.set('PYTHON', pyinst.full_path())
  cdata.set('pythondir', pyinst.get_install_dir())
endif

check_headers = [
  ['HAVE_ARPA_NAMESER_H', 'arpa/nameser.h'],
  ['HAVE_GSSAPI_GSSAPI_GENERIC_H', 'gssapi/gssapi/generic.h', gssapi],
  ['HAVE_GSSAPI_GSSAPI_H', 'gssapi/gssapi.h', gssapi],
  ['HAVE_GSSAPI_H', 'gssapi.h', gssapi],
  ['HAVE_GSS_H', 'gss.h', gssapi],
  ['HAVE_HESIOD_H', 'hesiod.h'],
  ['HAVE_INTTYPES_H', 'inttypes.h'],
  ['HAVE_LANGINFO_H', 'langinfo.h'],
  ['HAVE_MEMORY_H', 'memory.h'],
  ['HAVE_RESOLV_H', 'resolv.h'],
  ['HAVE_STDINT_H', 'stdint.h'],
  ['HAVE_STDLIB_H', 'stdlib.h'],
  ['HAVE_STRINGS_H', 'strings.h'],
  ['HAVE_STRING_H', 'string.h'],
  ['HAVE_SYS_FCNTL_H', 'sys/fcntl.h'],
  ['HAVE_SYS_FILIO_H', 'sys/filio.h'],
  ['HAVE_SYS_ITIMER_H', 'sys/itimer.h'],
  ['HAVE_SYS_STAT_H', 'sys/stat.h'],
  ['HAVE_SYS_TYPES_H', 'sys/types.h'],
  ['HAVE_UNISTD_H', 'unistd.h'],
  ['HAVE_WOLFSSL_OPTIONS_H', 'wolfssl/options.h', tls_library_dep],
  ['ENABLE_NLS', 'libintl.h'],
]

foreach h : check_headers
  deps = []
  if h.length() > 2
    deps = h.get(2)
  endif
  if cc.has_header(h.get(1), dependencies: deps)
    cdata.set(h.get(0), 1)
  endif
endforeach

check_declarations = [
  ['GSS_C_NT_HOSTBASED_SERVICE', 'gssapi.h', gssapi],
  ['h_errno',                 'netdb.h', []],
  ['PATH_MAX',                'limits.h', []],
  ['LIBRESSL_VERSION_NUMBER', 'openssl/ssl.h', tls_library_dep],
  ['TLS1_2_VERSION',          'openssl/ssl.h', tls_library_dep],
  ['TLS1_3_VERSION',          'openssl/ssl.h', tls_library_dep],
]

foreach f : check_declarations
  cdata.set10('HAVE_DECL_'+f.get(0).to_upper(),
              cc.has_header_symbol(f.get(1), f.get(0),
		dependencies: f.get(2),
                args: f.length() >= 4 ? f.get(3) : []))
endforeach

check_symbols = [
  # ['getopt_long', 'getopt.h'],
]

foreach f : check_symbols
  if cc.has_header_symbol(f.get(1), f.get(0))
    cdata.set('HAVE_'+f.get(0).to_upper(), 1)
  endif
endforeach

check_functions = [
# check token ['HAVE_CFLOCALECOPYCURRENT']
# check token ['HAVE_CFPREFERENCESCOPYAPPVALUE']
  ['dcgettext', '#include <libintl.h>'],
  ['explicit_bzero', '#include <string.h> #include <strings.h>'],
  ['getopt_long', '#include <getopt.h>'],
  ['gettext', '#include <libintl.h>'],
# check token ['HAVE_ICONV']
  ['inet_aton', '#include<arpa/inet.h>'],
# check token ['HAVE_LIB45']
# check token ['HAVE_LIBCRYPTO']
# check token ['HAVE_LIBINET']
# check token ['HAVE_LIBKRB5']
# check token ['HAVE_LIBOPIE']
# check token ['HAVE_LIBSOCKET']
# check token ['HAVE_LIBSOCKS']
# check token ['HAVE_LIBSOCKS5']
# check token ['HAVE_PKG_hesiod']
# check token ['HAVE_SOCKS']
  ['res_search', '#include <resolv.h>'],
  ['stpcpy',    '#include <string.h>'],
  ['strlcat',   '#include <string.h>'],
  ['strlcpy',   '#include <string.h>'],
  ['strsignal', '#include <string.h>'],
  ['vsyslog',   '#include <syslog.h>'],
]

foreach f : check_functions
  if cc.has_function(f.get(0), prefix : f.get(1))
    cdata.set('HAVE_'+f.get(0).to_upper(), 1)
  endif
endforeach

cdata.set('SIZEOF_INT', cc.sizeof('int'))
cdata.set('SIZEOF_LONG', cc.sizeof('long'))
cdata.set('SIZEOF_LONG_LONG', cc.sizeof('long long'))
cdata.set('SIZEOF_SHORT', cc.sizeof('short'))

cdata.set('PROJECT_NAME', meson.project_name())
cdata.set('VERSION', meson.project_version())
cdata.set('MESON_INSTALL_PREFIX', get_option('prefix'))

configure_file(input : 'config.h.meson',
  output : 'config.h',
  configuration : cdata)

if not (1 == cdata.get('HAVE_GETOPT_LONG'))
  fetchmail_sources = [fetchmail_sources, 'lib/getopt.c', 'lib/getopt1.c', 'lib/getopt.h']
  message('adding local getopt.*')
endif

# helper library for easier build with common subroutines
fmlib = static_library('fm', sources:
  [ 'base64.c',
    'daemon.c',
    'escapes.c',
    'lib/explicit_bzero.c',
    'getpass.c',
    'report.c',
    'rfc822.c',
    'sdump.c',
    'lib/strlcat.c',
    'lib/strlcpy.c',
    'util.h', 'util.c',
    'xmalloc.c'])

fetchmail_exe = executable('fetchmail',
  fetchmail_sources, lexer, parser,
  dependencies: link_deps,
  link_with: fmlib,
  install: true)
manpage = configure_file(input: 'fetchmail.man', output: 'fetchmail.1', configuration: cdata)
install_man(manpage)

# fetchmailconf
if pyinst.found()
  pyinst.install_sources('fetchmailconf.py')
  fmcwrap = configure_file(input: 'fetchmailconf.in', output: 'fetchmailconf', configuration: cdata)
  fmcman = configure_file(input: 'fetchmail.man', output: 'fetchmailconf.1', configuration: cdata)
  install_data(fmcwrap, install_mode: 'rwxr-xr-x', install_dir: get_option('bindir'))
  install_man(fmcman)
endif

# test executables for developer use (not linked to self-tests)
executable('rfc822valid', 'rfc822valid.c',  c_args:'-DTEST')
executable('util',        'util.c',         c_args:'-DTEST', link_with: fmlib)
executable('base64',      'base64.c',       c_args:'-DTEST', link_with: fmlib)
executable('rfc822',      'rfc822.c',       c_args:'-DTEST', link_with: fmlib)
executable('rfc2047e',    'rfc2047e.c',     c_args:'-DTEST', link_with: fmlib, dependencies: intl_library)

executable('mxget',       'mxget.c',        c_args:['-DSTANDALONE', '-DHAVE_CONFIG_H'])

executable('netrc',       'netrc.c',        c_args:['-DSTANDALONE', '-DHAVE_CONFIG_H'], link_with: fmlib, dependencies: intl_library)
executable('unmime',      'unmime.c',       c_args:['-DSTANDALONE', '-DHAVE_CONFIG_H'], link_with: fmlib, dependencies: intl_library)
executable('test_getpassword', 'test_getpassword.c',  link_with: fmlib)

# check_PROGRAMS used for self-tests
x509_name_match_exe = executable('x509_name_match', 'x509_name_match.c', c_args:'-DTEST')
fm_realpath_exe =     executable('fm_realpath', 'fm_realpath.c', c_args:'-DTEST', link_with: fmlib, dependencies: intl_library)
tls_aux_exe =         executable('tls-aux', 'tls-aux.c', c_args:'-DTEST', dependencies: tls_library_dep, link_with: [fmlib])

# tests
testenv = environment()
testenv.set('srcdir', meson.current_source_dir())
foreach i : [
  't.smoke',
  't.validate-xhtml10', 
  't.validate-xhtml', 
  't.x509_name_match', 
  't.realpath', 
  't.tls-aux', 
  't.operation',
]
  test_script = find_program(i, dirs: meson.current_source_dir())
  test(i, test_script, env: testenv)
endforeach

# FIXME: translations
# FIXME: rsync

# git-check covered by meson dist

# documentation
asciidoc =  find_program('asciidoc', required: need_maint_tools)
pandoc =    find_program('pandoc', required: need_maint_tools)
rst2html =  find_program('rst2html5.py', 'rst2html5', required: need_maint_tools)
htmldoc =   find_program('htmldoc', meson.current_source_dir() / 'dist-tools' / 'htmldoc', required: need_maint_tools)
sed =       find_program('gsed', 'sed')
awk =       find_program('gawk', 'nawk', 'awk')

docdir = get_option('datadir') / 'doc' / meson.project_name()
doctag = 'doc'

if asciidoc.found()
doc_mailboxnames = custom_target(
  input: 'Mailbox-Names-UTF7.txt', output: '@BASENAME@.html',
  command: [asciidoc, '--unsafe', '--attribute=toc', '--attribute=data-uri', '-o' , '@OUTPUT@', '@INPUT@'],
  install: true, install_tag: doctag, install_dir: docdir
)
else
install_data('Mailbox-Names-UTF7.html', install_dir: docdir, install_tag: doctag)
endif

if pandoc.found() and rst2html.found()
tmp_fetchmail_man_rst = custom_target(
  input: 'fetchmail.man', output: '@BASENAME@.rst',
  command: [pandoc, '--from=man', '--to=rst', '--table-of-contents', '--standalone', '--output', '@OUTPUT@', '@INPUT@']
)
tmp_fetchmail_man_html = custom_target(
  input: tmp_fetchmail_man_rst, output: '@BASENAME@.html',
  command: [rst2html, '--title', 'Fetchmail Manual', '--strip-comments', '--rfc-references', '@INPUT@', '@OUTPUT@'],
)
doc_fetchmail_man_html = custom_target(
  input: tmp_fetchmail_man_html, output: '@BASENAME@-man.html',
  command: [sed, '-E', '-f', meson.current_source_dir() / 'delete-colgroup.sed', '@INPUT@'],
  capture: true,
  install: true, install_tag: doctag, install_dir: docdir
)
else
install_data('fetchmail-man.html', install_dir: docdir, install_tag: doctag)
endif

if htmldoc.found()
tmp_fetchmail_faq_print = custom_target(
  input: 'fetchmail-FAQ.html',
  output: 'fetchmail-FAQ-print.html',
  command: [awk, '/^[ \t]*<h1/ {sec++; } {if (sec < 2 || sec > 3) print $0;}', '@INPUT@'],
  capture: true
)
doc_fetchmail_faq_pdf = custom_target(
  input: [tmp_fetchmail_faq_print, 'fetchmail-FAQ.book', 'bighand.png'],
  output: 'fetchmail-FAQ.pdf',
  command: [htmldoc, '--logoimage', meson.current_source_dir() / 'bighand.png', 
                     '--batch',     meson.current_source_dir() / 'fetchmail-FAQ.book'],
  env:     myenv,
  install: true, install_tag: doctag, install_dir: docdir
)
else
install_data('fetchmail-FAQ.pdf', install_dir: docdir, install_tag: doctag)
endif

install_data([
  'fetchmail-features.html',
  'gpl-3.0.txt',
  'design-notes.html', 'esrs-design-notes.html',
  'todo.html', 'TODO.txt',
  'NEWS', 'OLDNEWS',
  'README', 
  'README.NTLM', 
  'README.packaging', 
  'README.SSL', 
  'README.SSL-SERVER', 
  'fetchmail-SA-2026-01.txt',
  'fetchmail-SA-2025-01.txt',
  'fetchmail-SA-2021-02.txt',
  'fetchmail-SA-2021-01.txt',
  'fetchmail-SA-2012-02.txt',
  'fetchmail-SA-2012-01.txt',
  'fetchmail-SA-2011-01.txt',
  'fetchmail-EN-2010-03.txt',
  'fetchmail-SA-2010-02.txt',
  'fetchmail-SA-2010-01.txt',
  'fetchmail-SA-2009-01.txt',
  'fetchmail-SA-2008-01.txt',
  'fetchmail-SA-2007-02.txt',
  'fetchmail-SA-2007-01.txt',
  'fetchmail-SA-2006-03.txt',
  'fetchmail-SA-2006-02.txt',
  'fetchmail-SA-2006-01.txt',
  'fetchmail-SA-2005-01.txt',
  'fetchmail-SA-2005-02.txt',
  'fetchmail-SA-2005-03.txt',
  ],
  install_dir: docdir, install_tag: doctag,
)

meson.add_dist_script('meson-dist-script.sh')
