(use-modules

  (gnu packages cpio)
  (gnu packages cups)
  (gnu packages image)
  (gnu packages package-management)

  (xyz euandreh queue)
  (gnu packages mail)
  (gnu packages admin)
  (guix download)
  (guix build-system gnu)
  ((guix licenses) #:prefix license:)
  (guix records)
  (gnu services mail)
  (gnu services shepherd)
  (gnu system setuid)
  (gnu packages dbm)
  (gnu packages cyrus-sasl)
  (gnu packages onc-rpc)
  (gnu packages tls)
  (gnu packages perl)
  (gnu packages m4)
  (guix utils)


  ((xyz euandreh heredoc) #:prefix heredoc:)
  (gnu bootloader)
  (gnu bootloader grub)
  (gnu packages)
  (gnu services base)
  (gnu services cups)
  (gnu services desktop)
  (gnu services docker)
  (gnu services pm)
  (gnu services security-token)
  (gnu services sound)
  (gnu services ssh)
  (gnu services virtualization)
  (gnu services vpn)
  (gnu services xorg)
  (gnu system keyboard)
  (gnu system file-systems)
  (gnu system locale)
  (gnu system mapped-devices)
  (guix gexp)
  (guix packages)
  (nongnu packages linux)
  (nongnu system linux-initrd)
  (srfi srfi-1)
  (xyz euandreh queue))
(heredoc:enable-syntax)

(define-public epson-L365-x
  (package
    (name "epson-L365-x")
    (version "1.0.0")
    (source
      (origin
        (method url-fetch)
        (uri
          (string-append
           "https://download3.ebz.epson.net/dsc/f/03/00/03/45/41/92e9c9254f0ee4230a069545ba27ec2858a2c457/epson-inkjet-printer-201401w-"
           version
           "-1lsb3.2.src.rpm"))
        (sha256
          (base32 "0c60m1sd59s4sda38dc5nniwa7dh1b0kv1maajr0x9d38gqlyk3x"))))
    (build-system gnu-build-system)
    (arguments
      (list
       #:phases
       #~(modify-phases %standard-phases
          (replace 'unpack
            (lambda* (#:key outputs #:allow-other-keys)
              (mkdir "source")
              (chdir "source")
              (system (string-append "rpm2cpio " #$source " | cpio -idv"))
              (invoke "tar" "-xvf" (string-append "epson-inkjet-printer-201401w-" #$version ".tar.gz"))
              (invoke "tar" "-xvf" (string-append "epson-inkjet-printer-filter-"  #$version ".tar.gz"))))
          (add-after 'unpack 'patch-/opt-paths
            (lambda _
              (substitute* (find-files (string-append "epson-inkjet-printer-201401w-" #$version "/ppds/"))
                (("/opt/epson-inkjet-printer-201401w/cups/lib")
                 (string-append (assoc-ref outputs "out")
                                "/lib/cups")))
              (substitute* (find-files (string-append "epson-inkjet-printer-201401w-" #$version "/ppds/"))
                (("/opt/epson-inkjet-printer-201401w/watermark")
                 (string-append (assoc-ref outputs "out")
                                "/watermark")))))
          (add-after 'unpack 'chdir-into-builddir
            (lambda _
              (chdir (string-append "epson-inkjet-printer-filter-" #$version))))
          (add-after 'install 'install-extra-files
            (lambda* (#:key outputs #:allow-other-keys)
              (let* ((out (assoc-ref outputs "out"))
                     (model-dir (string-append out "/share/cups/model/epson-inkjet-printer-201401w")))
                (chdir (string-append "../epson-inkjet-printer-201401w-" #$version))
                (mkdir-p model-dir)
                (invoke "cp" "-a" "ppds" model-dir)
                (invoke "cp" "-a" "lib64" "resource" "watermark" out)))))))
    (native-inputs
      (list cpio
            cups-minimal
            libjpeg-turbo
            rpm))
    (synopsis
     "Epson printer driver (L456, L455, L366, L365, L362, L360, L312, L310, L222, L220, L132, L130)")
    (description
     "This software is a filter program used with the Common UNIX Printing
System (CUPS) under Linux.  It supplies high quality printing with
Seiko Epson Color Ink Jet Printers.")
    (home-page "https://www.openprinting.org/driver/epson-201401w")
    ;; Plus the "SEIKO EPSON CORPORATION SOFTWARE LICENSE AGREEMENT":
    ;; https://epson.com/SoftwareLicenseAgreement
    (license license:lgpl2.1)))

(define whoami "andreh")
(define priv-statedir (string-append "/var/lib/" whoami))
(define toph "toph")
(define toph.tld "euandre.org")

(define-record-type* <postfix-configuration>
  postfix-configuration
  make-postfix-configuration
  postfix-configuration?
  (postfix         postfix-configuration-postfix         (default postfix))
  (set-sendmail?   postfix-configuration-set-sendmail?   (default #t))
  (master.cf-file  postfix-configuration-master.cf-file  (default #f))
  (main.cf-file    postfix-configuration-main.cf-file    (default #f))
  (master.cf-extra postfix-configuration-master.cf-extra (default ""))
  (main.cf-extra   postfix-configuration-main.cf-extra   (default ""))
  (data-directory  postfix-configuration-data-directory  (default "/var/lib/postfix"))
  (queue-directory postfix-configuration-queue-directory (default "/var/spool/postfix"))
  (user            postfix-configuration-user            (default "postfix"))
  (group           postfix-configuration-group           (default "postfix"))
  (setgid-group    postfix-configuration-setgid-group    (default "postdrop"))
  (root-aliases    postfix-configuration-root-aliases    (default '("abuse" "admin" "hostmaster" "postmaster")))
  (cert-file       postfix-configuration-cert-file       (default #f))
  (key-file        postfix-configuration-key-file        (default #f))
  (hostname        postfix-configuration-hostname        (default (gethostname))))

(define (generate-master.cf config)
  (match-record config <postfix-configuration>
      (master.cf-extra)
    (format #f
     #"-
       # ============================================================================================================
       # service   type       private  unpriv  chroot  wakeup   maxproc  command + args
       #                      (yes)    (yes)   (no)    (never)  (100)
       # =============================================================================================================


       anvil       unix       -        -       n       -        1        anvil
       bounce      unix       -        -       n       -        0        bounce
       cleanup     unix       n        -       n       -        0        cleanup
       defer       unix       -        -       n       -        0        bounce
       discard     unix       -        -       n       -        -        discard
       error       unix       -        -       n       -        -        error
       flush       unix       n        -       n       1000?    0        flush
       lmtp        unix       -        -       n       -        -        lmtp
       local       unix       -        n       n       -        -        local
       pickup      unix       n        -       n       60       1        pickup
       proxymap    unix       -        -       n       -        -        proxymap
       proxywrite  unix       -        -       n       -        1        proxymap
       qmgr        unix       n        -       n       300      1        qmgr
       relay       unix       -        -       n       -        -        smtp
       retry       unix       -        -       n       -        -        error
       rewrite     unix       -        -       n       -        -        trivial-rewrite
       scache      unix       -        -       n       -        1        scache
       showq       unix       n        -       n       -        -        showq
       smtp        unix       -        -       n       -        -        smtp
       smtp        inet       n        -       n       -        -        smtpd -v -o syslog_name=postfix/smtp
       tlsmgr      unix       -        -       n       1000?    1        tlsmgr
       trace       unix       -        -       n       -        0        bounce
       verify      unix       -        -       n       -        1        verify
       virtual     unix       -        n       n       -        -        virtual
       postlog     unix-dgram n        -       n       -        1        postlogd
       ~a
       "#
     master.cf-extra)))

(define (generate-main.cf config)
  (match-record config <postfix-configuration>
      (postfix queue-directory data-directory user setgid-group hostname main.cf-extra)
    (format #f
     #"-
       compatibility_level = 3.6

       mynetworks = 127.0.0.0/8

       queue_directory = ~a
       data_directory = ~a
       mail_owner = ~a
       setgid_group = ~a

       # myhostname = ~a
       # mydestination = $myhostname, $mydomain, localhost.$mydomain, localhost

       alias_maps = hash:/etc/aliases

       home_mailbox = Mail/Inbox

       header_checks = regexp:{ { /^Received:.*/ IGNORE }, { /^X-Originating-IP:.*/ IGNORE } }
       ~a

       sender_dependent_relayhost_maps = hash:~a/postfix/relayhosts-maps
       smtp_sasl_auth_enable = yes
       smtp_sasl_password_maps = hash:~a/postfix/sasl-password
       smtp_sasl_security_options = noanonymous
       smtp_tls_security_level = encrypt
       smtp_tls_note_starttls_offer = yes
       smtp_use_tls = yes
       smtp_sender_dependent_authentication = yes
       smtp_sasl_mechanism_filter = login, plain
       "#
     queue-directory
     data-directory
     user
     setgid-group
     hostname
     ;; hostname
     main.cf-extra
     priv-statedir
     priv-statedir)))

(define (postfix-etc-files config)
  (match-record config <postfix-configuration>
      (master.cf-file main.cf-file)
    `(("postfix"
       ,(file-union
         "postfix"
         `(("master.cf" ,(plain-file "master.cf" (or master.cf-file (generate-master.cf config))))
           ("main.cf"   ,(plain-file "main.cf"   (or main.cf-file   (generate-main.cf   config))))))))))

(define (postfix-accounts config)
  (match-record config <postfix-configuration>
      (user group setgid-group)
    (list
     (user-account
       (name user)
       (group group)
       (comment "Postfix system user")
       (home-directory "/var/empty")
       (shell (file-append shadow "/sbin/nologin"))
       (system? #t))
     (user-group
       (name group)
       (system? #t))
     (user-group
       (name setgid-group)
       (system? #t)))))

(define (postfix-setuid-programs config)
  (match-record config <postfix-configuration>
      (postfix setgid-group set-sendmail?)
    (append
     (list
      (setuid-program
        (program (file-append postfix "/sbin/postdrop"))
        (setuid? #f)
        (setgid? #t)
        (group setgid-group))
      (setuid-program
        (program (file-append postfix "/sbin/postqueue"))
        (setuid? #f)
        (setgid? #t)
        (group setgid-group)))
     (if set-sendmail?
       (list
        (setuid-program
          (program (file-append postfix "/sbin/sendmail"))
          (setuid? #f)
          (setgid? #t)
          (group setgid-group)))
       '()))))

(define (postfix-activation config)
  (match-record config <postfix-configuration>
      (queue-directory)
    #~(begin
        (use-modules (guix build utils))
        (let ((user (getpwnam "root")))
          (format (current-error-port)
           "Creating Postfix queue directory: \"~a\".~%" #$queue-directory)
          (mkdir-p #$queue-directory)
          (chown #$queue-directory (passwd:uid user) (passwd:gid user))
          (chmod #$queue-directory #o755)
          (format (current-error-port)
           "Creating email spool director: \"/var/mail\".~%")
          (mkdir-p "/var/mail")))))

(define (postfix-shepherd-service config)
  (match-record config <postfix-configuration>
      (postfix data-directory)
    (list
     (shepherd-service
       (provision '(postfix))
       (documentation
         #"-
           Run the Postfix MTA.

           This is the entrypoint for starting the "master" process.  Then the
           "master" process itself takes responsability of starting all the
           required daemons and commands."#)
       (start #~(make-forkexec-constructor
                 (list
                  #$(file-append postfix "/sbin/postfix")
                  "-v"
                  "start-fg")
                 #:pid-file (string-append #$data-directory "/master.lock")))
       (stop #~(make-kill-destructor))
       (actions
         (list
          (shepherd-action
            (name 'reload)
            (documentation
              #"-
                Re-read the "master.cf" and "main.cf" configuration files.

                Daemon processes terminate when possible, and when restarted
                use the values of the new configuration files.

                This live-reload option is usually preferable over a stop/start
                cycle, as it incurs in no interruption of the running service."#)
            (procedure
              #~(lambda _
                  (invoke #$(file-append postfix "/sbin/postfix") "reload"))))))))))

(define (postfix-aliases config)
  (match-record config <postfix-configuration>
      (root-aliases)
    (map (lambda (alias)
           `(,alias "root"))
         root-aliases)))

(define postfix-service-type
  (service-type
    (name 'postfix)
    (extensions
      (list
       (service-extension etc-service-type
                          postfix-etc-files)
       (service-extension account-service-type
                          postfix-accounts)
       (service-extension setuid-program-service-type
                          postfix-setuid-programs)
       (service-extension activation-service-type
                          postfix-activation)
       (service-extension mail-aliases-service-type
                          postfix-aliases)
       (service-extension profile-service-type
                          (compose list postfix-configuration-postfix))
       (service-extension shepherd-root-service-type
                          postfix-shepherd-service)))
    (default-value (postfix-configuration))
    (description
      #"-
        Run the Postfix MTA.

        This is the top-level system service for Postfix.

        It includes:
        - populating /etc/postfix/ with read-only configuration files;
        - the user and groups used by Postfix when handling email delivery;
        - the special setgid binaries for daily usage, such as "sendmail";
        - the Shepherd service for starting, stopping and *reloading* the
          service without restarting it;
        - the activation script for creating the required directories and
          configuring them with the correct permissions;
        - the binaries in the system profile so that one doesn't need to explicilty
          include the package when the service is already enabled.

        An extension to the log-rotation service isn't included: the default
        rottlog configuration already includes /var/log/maillog in its routine,
        so it is kept out.

        The defaults of <postfix-configuration> provide sane default values for
        most things, such as group names, data and queue directories, etc.  When
        used as-is, it creates a Postfix server that sends email from local users
        of the domain provided by "/etc/hostname"."#)))

(operating-system
  (kernel linux)
  (initrd microcode-initrd)
  (firmware (list linux-firmware))
  (locale "fr_FR.UTF-8")
  (locale-definitions
    (append
     (list
      (locale-definition
        (name "pt_BR.UTF-8")
        (source "pt_BR")))
     %default-locale-definitions))
  (timezone "America/Sao_Paulo")
  (keyboard-layout
    (keyboard-layout "br" #:options '("caps:swapescape" "esperanto:qwerty")))
  (host-name "velhinho")
  (hosts-file
    (plain-file
     "hosts"
     (format #f
      #"-
        127.0.0.1 localhost
        ::1       localhost

        10.0.0.0 ~a
        10.0.0.1 ~a
        "#
      toph
      host-name)))
  (users
    (append
     (list
      (user-account
        (name whoami)
        (comment "EuAndreh")
        (group "users")
        (supplementary-groups '("netdev" "audio" "video" "wheel" "kvm" "docker"
                                "cache" "brightness"))))
      %base-user-accounts))
  (groups
    (append
     (list
      (user-group
        (name "cache"))
      (user-group
        (name "brightness")))
     %base-groups))
  (packages
    (append
     (map (compose list specification->package+output symbol->string)
          '(nss-certs
            i3-wm))
     (list)
     (remove (lambda (package)
               (equal? "wget" (package-name package)))
             %base-packages)))
  (services
    (append
     (list
      (service bluetooth-service-type)
      (service tlp-service-type)
      (service thermald-service-type)
      (service pcscd-service-type)
      (service docker-service-type)
      (service libvirt-service-type)
      (service virtlog-service-type)
      (service xfce-desktop-service-type)
      (service mate-desktop-service-type)
      (service lxqt-desktop-service-type)
      (service enlightenment-desktop-service-type)
      (service gnome-desktop-service-type)
      (service gnome-keyring-service-type)
      (simple-service 'create-/var/lib/euandreh activation-service-type
        #~(begin
            (use-modules (guix build utils))
            (let ((user (getpwnam #$whoami)))
              (format (current-error-port)
               "Creating system-level private state directory: \"~a\".~%" #$priv-statedir)
              (mkdir-p #$priv-statedir)
              (chown #$priv-statedir (passwd:uid user) (passwd:gid user))
              (chmod #$priv-statedir #o700))))
      (service postfix-service-type)
      (service mail-aliases-service-type
        `(("root" ,whoami)))
      (service wireguard-service-type
        (wireguard-configuration
          (addresses '("10.0.0.1/32"))
          (peers
            (list
             (wireguard-peer
               (name toph)
               (endpoint (string-append toph.tld ":51820"))
               (public-key "8jJgTIWrs7HNWlJXOwl8A0DKqIiAGa4hhh/hcXm4EUs=")
               (allowed-ips '("10.0.0.0/32"))
               (keep-alive 25))))))
      (service qemu-binfmt-service-type
        (qemu-binfmt-configuration
          (platforms
            (lookup-qemu-platforms "arm" "aarch64"))))
      (service cups-service-type
        (cups-configuration
          (web-interface? #t)
          (extensions
            (list epson-L365-x))))
      (service openssh-service-type
        (openssh-configuration
          (password-authentication? #f)
          (authorized-keys
            `((,whoami ,(local-file
                        (string-append (or (getenv "XDG_CONFIG_HOME")
                                           (string-append (getenv "HOME") "/.ssh"))
                                       "/ssh/id_rsa.pub")))))
          (extra-content #"-
            ClientAliveInterval 30
            ClientAliveCountMax 20
            MaxSessions 20
            "#)))
      #;
      (udev-rules-service
        'backlight
        (udev-rule
         "backlight.rule"
         (string-replace
          #"-
            ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="@DEVICE@", GROUP="video", MODE="0664"
            "#
          "@DEVICE@"
          (getenv "BACKLIGHT_DEVICE"))))
      (set-xorg-configuration
        (xorg-configuration
          (keyboard-layout keyboard-layout)
          (extra-config
            (list
             #"-
               Section "InputClass"
                   Identifier "touchpad"
                   Driver "libinput"
                   MatchIsTouchpad "on"
                   Option "Tapping" "on"
               EndSection
               Section "Device"
                   Identifier  "Intel Graphics"
                   Driver      "intel"
                   Option      "Backlight"  "intel_backlight"
               EndSection
               "#)))))
     (modify-services %desktop-services
       (pulseaudio-service-type config =>
         (pulseaudio-configuration
           (inherit config)
           (extra-script-files
             (list
              (plain-file
               "noise-cancelling.pa"
               #"-
                 load-module module-echo-cancel
                 "#)))))
       (guix-service-type config =>
         (guix-configuration
           (inherit config)
           (substitute-urls
             (append
              '("https://substitutes.nonguix.org")
              %default-substitute-urls))
           (authorized-keys
             (append
              (list
               (plain-file
                "non-guix.pub"
                #"-
                  (public-key
                    (ecc
                      (curve Ed25519)
                      (q #C1FD53E5D4CE971933EC50C9F307AE2171A2D3B52C804642A7A35F84F3A4EA98#)))
                  "#))
              %default-authorized-guix-keys)))))))
  (bootloader
    (bootloader-configuration
      (bootloader grub-efi-bootloader)
      (targets '("/boot/efi"))
      (keyboard-layout keyboard-layout)))
  (mapped-devices
    (list
     (mapped-device
       (source (uuid "6b0d38a6-d93e-4f8e-a59a-7729f5adf892"))
       (target "cryptroot")
       (type luks-device-mapping))))
  (file-systems
    (append
     (list
      (file-system
        (mount-point "/boot/efi")
        (device (uuid "1B26-9F4E" 'fat32))
        (type "vfat"))
      (file-system
        (mount-point "/")
        (device "/dev/mapper/cryptroot")
        (type "ext4")
        (dependencies mapped-devices)))
     %base-file-systems)))
