cmake_minimum_required(VERSION 3.22)
project(LanternTerminal VERSION 0.5.0 LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 6.8 REQUIRED COMPONENTS Widgets Network SerialPort PrintSupport Core5Compat)
set(LUA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/lua-5.4.9")
file(GLOB LUA_SOURCES "${LUA_DIR}/src/*.c")
list(REMOVE_ITEM LUA_SOURCES "${LUA_DIR}/src/lua.c" "${LUA_DIR}/src/luac.c")
add_library(lantern_lua_core STATIC ${LUA_SOURCES})
target_include_directories(lantern_lua_core PUBLIC "${LUA_DIR}/src")
if(NOT WIN32)
 target_compile_definitions(lantern_lua_core PRIVATE LUA_USE_LINUX)
 target_link_libraries(lantern_lua_core PUBLIC m ${CMAKE_DL_LIBS})
endif()
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/lua/lantern.lua")
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/lua/lantern.lua" LANTERN_LUA_MODULE)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/lua/syncterm.lua")
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/lua/syncterm.lua" LANTERN_SYNCTERM_MODULE)
configure_file(src/lua_module.h.in generated/lua_module.h @ONLY)
add_executable(lantern-lua src/lua_runner.cpp)
target_include_directories(lantern-lua PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/generated")
target_link_libraries(lantern-lua PRIVATE lantern_lua_core Qt6::Core Qt6::Network)
target_compile_definitions(lantern-lua PRIVATE LANTERN_VERSION="${PROJECT_VERSION}")
if(WIN32)
 target_link_libraries(lantern-lua PRIVATE shell32)
 target_compile_definitions(lantern-lua PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
endif()
set(VTERM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/third_party/libvterm-0.3.3")
file(GLOB VTERM_SOURCES "${VTERM_DIR}/src/*.c")
add_library(vterm STATIC ${VTERM_SOURCES})
target_include_directories(vterm PUBLIC "${VTERM_DIR}/include" PRIVATE "${VTERM_DIR}/src")
add_executable(lantern-terminal WIN32 src/main.cpp src/config.cpp src/commands.cpp src/launch.cpp src/workspace.cpp src/theme.cpp src/ssh_trace.cpp src/transport.cpp src/terminal.cpp src/sixel.cpp src/session.cpp src/zmodem.cpp src/xfer.cpp src/dialogs.cpp src/window.cpp src/agent_window.cpp src/update.cpp src/sync.cpp src/services.cpp)
add_dependencies(lantern-terminal lantern-lua)
# Built-in SSH engine (libssh). Without it the OpenSSH engine is the only choice.
option(LANTERN_WITH_LIBSSH "Build the built-in libssh SSH engine" ON)
set(LANTERN_LIBSSH_FOUND OFF)
if(LANTERN_WITH_LIBSSH)
 if(NOT CMAKE_CROSSCOMPILING)
  find_package(PkgConfig QUIET)
  if(PkgConfig_FOUND)
   pkg_check_modules(LIBSSH IMPORTED_TARGET libssh>=0.11)
  endif()
 endif()
 if(LIBSSH_FOUND)
  set(LANTERN_LIBSSH_FOUND ON)
  set(LANTERN_LIBSSH_TARGET PkgConfig::LIBSSH)
 else()
  # Windows cross builds: scripts/build-windows-libssh.sh installs libssh's CMake package.
  find_package(libssh 0.11 CONFIG QUIET)
  if(libssh_FOUND)
   set(LANTERN_LIBSSH_FOUND ON)
   set(LANTERN_LIBSSH_TARGET ssh)
  endif()
 endif()
 if(LANTERN_LIBSSH_FOUND)
  find_package(OpenSSL REQUIRED COMPONENTS Crypto)
 endif()
 if(NOT LANTERN_LIBSSH_FOUND)
  message(WARNING "libssh 0.11+ not found: building without the built-in SSH engine")
 endif()
endif()
function(lantern_use_libssh target)
 if(LANTERN_LIBSSH_FOUND)
  target_sources(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/ssh_libssh.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/ssh_tools.cpp)
  target_compile_definitions(${target} PRIVATE LANTERN_HAVE_LIBSSH)
  target_link_libraries(${target} PRIVATE ${LANTERN_LIBSSH_TARGET} OpenSSL::Crypto)
  if(WIN32)
   target_link_libraries(${target} PRIVATE ws2_32)
  endif()
 endif()
endfunction()
lantern_use_libssh(lantern-terminal)
# RDP sessions (FreeRDP 3). Without it the RDP protocol is not offered.
option(LANTERN_WITH_RDP "Build RDP sessions with FreeRDP" ON)
set(LANTERN_RDP_FOUND OFF)
if(LANTERN_WITH_RDP)
 if(NOT CMAKE_CROSSCOMPILING)
  find_package(PkgConfig QUIET)
  if(PkgConfig_FOUND)
   pkg_check_modules(FREERDP IMPORTED_TARGET freerdp3 freerdp-client3 winpr3)
  endif()
  if(FREERDP_FOUND)
   set(LANTERN_RDP_FOUND ON)
   set(LANTERN_RDP_TARGETS PkgConfig::FREERDP)
  endif()
 else()
  # Windows cross builds: scripts/build-windows-freerdp.sh installs FreeRDP's CMake packages.
  find_package(WinPR CONFIG QUIET)
  find_package(FreeRDP CONFIG QUIET)
  find_package(FreeRDP-Client CONFIG QUIET)
  if(FreeRDP-Client_FOUND AND FreeRDP_FOUND AND WinPR_FOUND)
   set(LANTERN_RDP_FOUND ON)
   set(LANTERN_RDP_TARGETS freerdp-client freerdp winpr)
  endif()
 endif()
 if(NOT LANTERN_RDP_FOUND)
  message(WARNING "FreeRDP 3 not found: building without RDP sessions")
 endif()
endif()
function(lantern_use_rdp target)
 if(LANTERN_RDP_FOUND)
  target_sources(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/rdp.cpp)
  target_compile_definitions(${target} PRIVATE LANTERN_HAVE_RDP)
  target_link_libraries(${target} PRIVATE ${LANTERN_RDP_TARGETS})
 endif()
endfunction()
lantern_use_rdp(lantern-terminal)
target_link_libraries(lantern-terminal PRIVATE Qt6::Widgets Qt6::Network Qt6::SerialPort Qt6::PrintSupport Qt6::Core5Compat vterm)
target_compile_definitions(lantern-terminal PRIVATE LANTERN_VERSION="${PROJECT_VERSION}")
if(WIN32)
 target_sources(lantern-terminal PRIVATE assets/windows-version.rc)
 target_compile_definitions(lantern-terminal PRIVATE _WIN32_WINNT=0x0A00 WIN32_LEAN_AND_MEAN NOMINMAX)
 target_link_libraries(lantern-terminal PRIVATE advapi32 user32 ole32 uuid shell32 ws2_32)
else()
 target_link_libraries(lantern-terminal PRIVATE util)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
 target_compile_options(lantern-terminal PRIVATE -Wall -Wextra -Wpedantic)
endif()
include(GNUInstallDirs)
install(TARGETS lantern-terminal lantern-lua RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY docs/ DESTINATION ${CMAKE_INSTALL_DATADIR}/lantern-terminal/docs)
install(DIRECTORY python/ DESTINATION ${CMAKE_INSTALL_DATADIR}/lantern-terminal/python OPTIONAL)
install(DIRECTORY lua/ DESTINATION ${CMAKE_INSTALL_DATADIR}/lantern-terminal/lua)
install(DIRECTORY examples/ DESTINATION ${CMAKE_INSTALL_DATADIR}/lantern-terminal/examples)
install(DIRECTORY third_party/licenses/ DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/lantern-terminal/licenses)
install(FILES third_party/libvterm-0.3.3/LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/lantern-terminal/licenses RENAME libvterm-MIT.txt)
install(FILES assets/lantern-terminal.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
install(FILES assets/lantern-terminal.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)
install(FILES LICENSE THIRD-PARTY.md DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/lantern-terminal)
set(CPACK_PACKAGE_NAME "lantern-terminal")
set(CPACK_PACKAGE_VENDOR "Lantern Terminal")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Tabbed terminal and connection manager")
set(CPACK_PACKAGE_CONTACT "Lantern Terminal maintainers")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
set(CPACK_PACKAGE_FILE_NAME "lantern-terminal-${PROJECT_VERSION}-linux-x64")
set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssh-client, python3")
set(CPACK_GENERATOR "DEB;TGZ")
include(CPack)
include(CTest)
option(LANTERN_BUILD_APPEARANCE_CHECK "Build the wizard appearance verification tool" OFF)
if(BUILD_TESTING OR LANTERN_BUILD_APPEARANCE_CHECK)
 add_executable(ssh-trace-check tests/ssh_trace_check.cpp src/ssh_trace.cpp)
 target_link_libraries(ssh-trace-check PRIVATE Qt6::Core)
 add_executable(appearance-check tests/appearance_check.cpp src/dialogs.cpp src/theme.cpp src/config.cpp src/commands.cpp)
 target_link_libraries(appearance-check PRIVATE Qt6::Widgets Qt6::SerialPort)
endif()
if(BUILD_TESTING AND NOT CMAKE_CROSSCOMPILING)
 find_package(Python3 REQUIRED COMPONENTS Interpreter)
 find_package(Qt6 REQUIRED COMPONENTS Test)
 add_executable(core-tests tests/core_tests.cpp src/config.cpp src/commands.cpp src/launch.cpp src/terminal.cpp src/sixel.cpp src/ssh_trace.cpp src/transport.cpp)
 target_link_libraries(core-tests PRIVATE Qt6::Widgets Qt6::Network Qt6::SerialPort Qt6::Test vterm util)
 add_test(NAME core COMMAND core-tests)
 set_tests_properties(core PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
 add_executable(workspace-tests tests/workspace_tests.cpp src/config.cpp src/commands.cpp src/launch.cpp src/workspace.cpp src/theme.cpp src/ssh_trace.cpp src/transport.cpp src/terminal.cpp src/sixel.cpp src/session.cpp src/zmodem.cpp src/xfer.cpp src/dialogs.cpp src/window.cpp src/agent_window.cpp src/update.cpp src/sync.cpp src/services.cpp)
 target_link_libraries(workspace-tests PRIVATE Qt6::Widgets Qt6::Network Qt6::SerialPort Qt6::Test Qt6::PrintSupport Qt6::Core5Compat vterm util)
 target_compile_definitions(workspace-tests PRIVATE LANTERN_VERSION="${PROJECT_VERSION}")
 add_dependencies(workspace-tests lantern-lua)
 lantern_use_libssh(workspace-tests)
 lantern_use_rdp(workspace-tests)
 add_test(NAME workspace COMMAND workspace-tests)
 set_tests_properties(workspace PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 30)
 add_test(NAME ssh-trace COMMAND ssh-trace-check /usr/bin/ssh)
 add_test(NAME appearance COMMAND appearance-check)
 set_tests_properties(appearance PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" TIMEOUT 10)
 add_test(NAME lua-safety COMMAND lantern-lua "${CMAKE_CURRENT_SOURCE_DIR}/tests/lua_safety.lua")
 set_tests_properties(lua-safety PROPERTIES ENVIRONMENT "LANTERN_SOCKET=;LANTERN_TOKEN=;LANTERN_TAB=" TIMEOUT 10)
 add_test(NAME lua-integration COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/lua_integration.py" "$<TARGET_FILE:lantern-terminal>")
 set_tests_properties(lua-integration PROPERTIES TIMEOUT 30)
 add_test(NAME tab-reuse COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/tab_reuse.py" "$<TARGET_FILE:lantern-terminal>")
 set_tests_properties(tab-reuse PROPERTIES TIMEOUT 30)
 add_test(NAME syncterm-compat COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/syncterm_compat.py" "$<TARGET_FILE:lantern-terminal>")
 set_tests_properties(syncterm-compat PROPERTIES TIMEOUT 60)
 if(LANTERN_RDP_FOUND)
  add_test(NAME rdp COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/rdp.py" "$<TARGET_FILE:lantern-terminal>")
  set_tests_properties(rdp PROPERTIES TIMEOUT 300)
 endif()
 add_test(NAME update COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/update.py" "$<TARGET_FILE:lantern-terminal>")
 set_tests_properties(update PROPERTIES TIMEOUT 60)
 add_test(NAME rlogin COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/rlogin.py" "$<TARGET_FILE:lantern-terminal>")
 set_tests_properties(rlogin PROPERTIES TIMEOUT 150)
 add_test(NAME bbs-session COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/bbs.py" "$<TARGET_FILE:lantern-terminal>")
 set_tests_properties(bbs-session PROPERTIES TIMEOUT 90)
 find_program(LANTERN_SZ sz)
 find_program(LANTERN_RZ rz)
 if(LANTERN_SZ AND LANTERN_RZ) # Zmodem checks need lrzsz
  add_test(NAME zmodem COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/zmodem.py" "$<TARGET_FILE:lantern-terminal>")
  set_tests_properties(zmodem PROPERTIES TIMEOUT 600)
  add_test(NAME xfer COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/xfer.py" "$<TARGET_FILE:lantern-terminal>")
  set_tests_properties(xfer PROPERTIES TIMEOUT 600)
 endif()
 if(LANTERN_LIBSSH_FOUND)
  add_test(NAME libssh-engine COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/libssh_engine.py" "$<TARGET_FILE:lantern-terminal>")
  set_tests_properties(libssh-engine PROPERTIES TIMEOUT 120)
  add_test(NAME ssh-tools COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/tests/ssh_tools.py" "$<TARGET_FILE:lantern-terminal>")
  set_tests_properties(ssh-tools PROPERTIES TIMEOUT 180)
 endif()
endif()
