# dezky EAS gateway — Z-Push (AGPLv3) wrapping Stalwart in Exchange
# ActiveSync so "Exchange" accounts on iOS/Android native Mail/Calendar get
# two-way mail + calendar + contacts sync. Z-Push talks to Stalwart with the
# client's own Basic credentials (mailbox password or app password) over
# IMAP/CalDAV/CardDAV — this container stores no secrets, only sync state.
#
# Z-Push 2.6.x speaks EAS up to 14.1. That covers native mobile clients but
# NOT the Outlook mobile app (Microsoft enforces EAS >= 16.1 there since
# March 2026) and not new Outlook for Windows (no EAS at all). See
# LICENSE-NOTES.md for the AGPL source-offer obligation.

ARG ZPUSH_VERSION=2.6.4

FROM alpine/git AS source
ARG ZPUSH_VERSION
RUN git clone --depth 1 --branch ${ZPUSH_VERSION} \
      https://github.com/EGroupware/z-push.git /z-push
# AWL (Andrew's Web Libraries) — Z-Push's CalDAV client (include/z_caldav.php)
# requires XMLDocument.php from it, and its include_path already expects the
# Debian location /usr/share/awl/inc. Debian dropped the php-awl package
# after bullseye, so vendor it from upstream at a pinned tag.
RUN git clone --depth 1 --branch r0.65 \
      https://gitlab.com/davical-project/awl.git /awl

# php:8.2 — the imap extension lives in PHP core through 8.3 and moved to
# PECL in 8.4; stay on a version where docker-php-ext-install still works.
# Pinned to the bookworm base: Debian trixie dropped the (upstream-dead)
# uw-imap libc-client packages the imap extension compiles against.
FROM php:8.2-apache-bookworm
ARG ZPUSH_VERSION

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
         libc-client2007e-dev libkrb5-dev libicu-dev \
    && docker-php-ext-configure imap --with-kerberos --with-imap-ssl \
    && docker-php-ext-install -j"$(nproc)" imap intl sysvshm sysvsem \
    && rm -rf /var/lib/apt/lists/*

COPY --from=source /z-push/src/ /usr/share/z-push/
COPY --from=source /awl/inc/ /usr/share/awl/inc/

# Main config: keep the 50+ upstream defaults, patch only what we change.
# The greps make the build fail loudly if an upstream config rename ever
# makes a sed miss instead of shipping a silently unconfigured gateway.
# (USE_FULLEMAIL_FOR_LOGIN is already true in the EGroupware fork.)
RUN sed -i \
      -e "s|define('TIMEZONE', '');|define('TIMEZONE', 'Europe/Copenhagen');|" \
      -e "s|define('BACKEND_PROVIDER', '');|define('BACKEND_PROVIDER', 'BackendCombined');|" \
      /usr/share/z-push/config.php \
    && grep -q "define('BACKEND_PROVIDER', 'BackendCombined')" /usr/share/z-push/config.php \
    && grep -q "define('USE_FULLEMAIL_FOR_LOGIN', true)" /usr/share/z-push/config.php

# PHP 8 fix (upstream Z-Push 2.6.4 bug): sem_get()/shm_attach() return
# objects instead of resources since PHP 8.0 and this debug log line
# sprintf's them — a fatal TypeError on every request. The rest of the
# provider only compares the handles against false, which is PHP 8-safe.
RUN sed -i \
      's|sprintf("%s(): Initialized mutexid %s and memid %s.", $class, $this->mutexid, $this->memid)|sprintf("%s(): Initialized shared memory mutex and segment.", $class)|' \
      /usr/share/z-push/backend/ipcsharedmemory/ipcsharedmemoryprovider.php \
    && grep -q "Initialized shared memory mutex and segment" \
         /usr/share/z-push/backend/ipcsharedmemory/ipcsharedmemoryprovider.php

# Backend + autodiscover configs are small files — full replacements.
COPY config/caldav.config.php   /usr/share/z-push/backend/caldav/config.php
COPY config/carddav.config.php  /usr/share/z-push/backend/carddav/config.php
COPY config/imap.config.php     /usr/share/z-push/backend/imap/config.php
COPY config/combined.config.php /usr/share/z-push/backend/combined/config.php
COPY config/autodiscover.config.php /usr/share/z-push/autodiscover/config.php

# Schema-sniffing autodiscover dispatcher (mobilesync → Z-Push, outlook
# schema → proxied to Stalwart). Lives inside autodiscover/ because
# autodiscover.php resolves its requires relative to that directory.
COPY autodiscover-router.php /usr/share/z-push/autodiscover/router.php

# Build-time smoke test: force-load every class the combined backend pulls
# in at runtime. Catches missing vendored dependencies (the AWL include
# above only crashes on the first *authenticated* request otherwise).
RUN php -d include_path='.:/usr/local/lib/php:/usr/share/z-push/:/usr/share/awl/inc' -r ' \
      require "/usr/share/z-push/vendor/autoload.php"; \
      foreach (array("CalDAVClient", "carddav_backend", "BackendIMAP", "BackendCalDAV", "BackendCardDAV", "BackendCombined") as $c) { \
        if (!class_exists($c)) { fwrite(STDERR, "FAILED loading $c\n"); exit(1); } \
      } \
      echo "class-load smoke OK\n";'

COPY apache/zpush.conf /etc/apache2/conf-available/zpush.conf
COPY php/zpush.ini /usr/local/etc/php/conf.d/zpush.ini
RUN a2enconf zpush \
    && mkdir -p /var/lib/z-push/state /var/log/z-push \
    && chown -R www-data:www-data /var/lib/z-push /var/log/z-push \
    && echo "${ZPUSH_VERSION}" > /usr/share/z-push/DEZKY_PINNED_VERSION

VOLUME /var/lib/z-push
EXPOSE 80
