M Makefile => Makefile +3 -1
@@ 51,4 51,6 @@ system-repl: channels-lock.scm
$(GUIX) repl -L modules -i ./repl-init.scm $(EXTRA_ARGS)
channels-lock.scm: channels.scm
- guix time-machine -C channels.scm $(EXTRA_TIMEMACHINE_ARGS) -- describe -f channels $(EXTRA_ARGS) > channels-lock.scm
+ guix time-machine -C channels.scm $(EXTRA_TIMEMACHINE_ARGS) -- \
+ describe -f channels $(EXTRA_ARGS) > channels-lock.scm \
+ || (rm channels-lock.scm && exit 1)
M config.scm => config.scm +77 -93
@@ 5,6 5,7 @@
(define-module (config))
(use-modules
+ (guix gexp)
(nongnu packages linux)
(nongnu system linux-initrd)
(nongnu packages firmware)
@@ 19,11 20,18 @@
(guix utils)
(guix packages)
(guix build-system gnu)
+ (guix build-system trivial)
(gnu system accounts)
(ruther services system)
(ruther services bind)
(ruther services nix-gl)
- (ruther bootloader grub))
+ (ruther services nix)
+ (ruther services auto-login)
+ (ruther services netbird)
+ (ruther packages netbird)
+ (ruther bootloader grub)
+ (dfsg contrib services tailscale))
+
(use-service-modules desktop sddm xorg base nix pm virtualization vpn
sound dbus cups containers security-token networking
ssh databases linux docker)
@@ 86,6 94,9 @@
'pluto-sdr
(file->udev-rule "53-adi-plutosdr-usb.rules" (local-file "udev/53-adi-plutosdr-usb.rules")))
(udev-rules-service
+ 'android
+ (file->udev-rule "51-android.rules" (local-file "udev/51-android.rules")))
+ (udev-rules-service
'ftdi
(file->udev-rule "51-ftdi.rules" (local-file "udev/51-ftdi.rules")))))
@@ 123,7 134,9 @@
(endpoint "159.195.49.157:51820")
(keep-alive 25)
(public-key "ZOVjmgUak67kLhNVgZwyb0bro3Yi4vCJbGArv+35IWQ=")
- (allowed-ips '("192.168.32.0/24")))))))))
+ (allowed-ips '("192.168.32.0/24")))))))
+ (service tailscaled-service-type)
+ (service netbird-service-type)))
(define %ruther/laptop-gui-essential-services
(list
@@ 175,7 188,7 @@
(define %ruther/base-laptop-os
(operating-system
- (kernel linux-6.18)
+ (kernel linux-7.2)
(kernel-arguments
(cons* "amdgpu.dcdebugmask=0x10"
%default-kernel-arguments))
@@ 236,10 249,10 @@
(program
(file-append inetutils "/bin/traceroute"))
(capabilities "cap_net_raw=eip"))
- (privileged-program
- (program
- (file-append wireshark-patched "/bin/dumpcap"))
- (capabilities "cap_net_raw,cap_net_admin=eip"))
+ ;; (privileged-program
+ ;; (program
+ ;; (file-append wireshark-patched "/bin/dumpcap"))
+ ;; (capabilities "cap_net_raw,cap_net_admin=eip"))
%default-privileged-programs))
;; This is where we specify system-wide packages.
@@ 251,10 264,11 @@
zip unzip
wget curl
vim
- nix
polkit ;; get pktty
fwupd-nonfree
- wireshark-patched)
+ netbird
+ ;; wireshark-patched
+ )
%base-packages))
(services
@@ 278,13 292,6 @@
(home "/home/fbw"))
%default-guix-shared-users))))
- ;; Prevent me from going to Codeberg too often.
- (simple-service 'disable-codeberg
- hosts-service-type
- (list
- (host "127.0.0.1" "www.codeberg.org")
- (host "127.0.0.1" "codeberg.org")))
-
;; I give up! Let the download binaries run.
(extra-special-file "/lib64/ld-linux-x86-64.so.2"
(file-append glibc "/lib/ld-linux-x86-64.so.2"))
@@ 294,20 301,48 @@
;; Let's use GUI apps from Nixpkgs, because, why not?
nixos-opengl-driver-service
- (service nix-service-type
+ ;; Prefer the builder's LAN address, then fall back to WireGuard.
+ (extra-special-file
+ "/root/.ssh/config"
+ (mixed-text-file
+ "root-ssh-config"
+ "Host edge-ruther-builder\n"
+ " HostName edge-ruther.local\n"
+ " HostKeyAlias edge-ruther.local\n"
+ " BatchMode yes\n"
+ " ConnectTimeout 5\n"
+ " ProxyUseFdpass yes\n"
+ " ProxyCommand "
+ (file-append bash "/bin/sh")
+ " -c '"
+ (file-append netcat-openbsd "/bin/nc")
+ " -F -w 2 edge-ruther.local %p || exec "
+ (file-append netcat-openbsd "/bin/nc")
+ " -F -w 10 192.168.32.12 %p'\n"))
+
+ (service nix-service-type/raised-nofile
(nix-configuration
(extra-config
'("experimental-features = nix-command flakes\n"
"extra-platforms = i686-linux aarch64-linux\n"
"keep-outputs = true\n"
- "keep-derivations = true\n"))))
+ "keep-derivations = true\n"
+
+ "extra-trusted-public-keys = edge-1:sGPnKl9kRZ1Tv8xqC8qdMfdpPpeZ0HDE38/eEmGOCGk=\n"
+ "fallback = true\n"
+
+ "builders = ssh-ng://nixremote@edge-ruther-builder x86_64-linux /root/.ssh/id_ed25519 8 2 big-parallel,kvm\n"
+ "builders-use-substitutes = true\n"))))
;; TODO: contribute this to the nix service
(simple-service 'nix-etc-d etc-profile-d-service-type
(list
(file-append nix "/etc/profile.d/nix-daemon.sh")
(file-append nix "/etc/profile.d/nix.sh")))
- ;; Vivado or Matlab can crash because they open too many files
+ ;; Vivado or Matlab can crash because they open too many files.
+ ;; Note: @nixbld limits are set on the nix-daemon shepherd
+ ;; service itself (see (ruther services nix)); PAM limits don't
+ ;; apply because nixbld users never log in.
(service pam-limits-service-type
(list
(pam-limits-entry "@wheel" 'hard 'nofile '50000)
@@ 322,7 357,9 @@
(local-file "keys/nonguix-signing-key.pub")
(local-file "keys/rpi-local-key.pub")
(local-file "keys/orv2-local-key.pub")))
- (substitute-urls '("https://substitutes.nonguix.org"))))
+ ;; (substitute-urls '("https://nonguix-proxy.ditigal.xyz"))
+ (substitute-urls '("https://substitutes.nonguix.org"))
+ ))
(service earlyoom-service-type
(earlyoom-configuration
@@ 355,8 392,9 @@
(mingetty-service-type config => (if (string=? (mingetty-configuration-tty config) "tty1")
(mingetty-configuration
(inherit config)
- (auto-login "ruther")
- (login-pause? #t))
+ (auto-login "auto")
+ (login-program (make-auto-login-program #:users '("ruther" "fbw")))
+ (login-pause? #f))
config))
(elogind-service-type config => (elogind-configuration
(handle-lid-switch-external-power 'ignore)))
@@ 380,93 418,39 @@
(ice-9 match)
(guix records))
-(define-record-type <non-grafted>
- (non-grafted derivation)
- non-grafted?
- (derivation non-grafted-derivation))
-
-(define-gexp-compiler (non-grafted-compiler (non-grafted <non-grafted>) system target)
- (mlet* %store-monad ((drv (non-grafted-derivation non-grafted)))
- (without-grafting
- (gexp->derivation "non-grafted"
- #~(symlink #$drv #$output)))))
-
-(define-record-type* <drv-name>
- drv-name-record drv-name
- drv-name?
- (derivation drv-name-derivation)
- (override-grafts? drv-name-override-grafts?
- (default #f)))
-
-(define-gexp-compiler (drv-name-compiler (drv-name <drv-name>) system target)
- (let ((drv-name-store (derivation->drv-name (drv-name-derivation drv-name))))
- (if (drv-name-override-grafts? drv-name)
- (without-grafting drv-name-store)
- drv-name-store)))
+(define (non-grafted file)
+ (computed-file
+ "non-grafted"
+ #~(symlink
+ #$(with-parameters
+ ((%graft? #f))
+ file)
+ #$output)))
(define <operating-system> (@@ (gnu system) <operating-system>))
(define-gexp-compiler (os-compiler (os <operating-system>) system target)
(operating-system-derivation os))
-;; I don't know why the inputs aren't getting grafted here, but they aren't, that's good here.
-(define (make-non-grafted-package pkgs)
- (package
- (name "non-grafted-pkg")
- (version "0")
- (synopsis #f)
- (source #f)
- (description #f)
- (home-page #f)
- (license #f)
- (build-system (@ (guix build-system trivial) trivial-build-system))
- ;; (inputs pkgs)
- (arguments
- (list
- #:builder #~(begin
- (use-modules
- (srfi srfi-19))
-
- (mkdir #$output)
-
- (for-each (lambda (pkg)
- (symlink
- pkg
- (string-append #$output "/" (basename pkg))))
- '#$pkgs)
-
- (symlink #$guile-3.0:debug (string-append #$output "/" "guile-debug"))
- (symlink #$(libc-utf8-locales-for-target):static (string-append #$output "/" "guile-debug"))
-
- ;; (for-each (lambda (pkg)
- ;; (unless (file-exists? (string-append #$output "/" (basename pkg)))
- ;; (symlink
- ;; pkg
- ;; (string-append #$output "/" (basename pkg)))))
- ;; (map cdr %build-inputs))
- )))))
-
;; Takes an operating system and gc roots its derivation
(define (operating-system-with-build-inputs os)
(operating-system
(inherit os)
- (services (operating-system-user-services os))
(services
(cons*
(simple-service 'gc-root-system-derivation
gc-root-service-type
(list
- (drv-name (operating-system-derivation os) #t)
- (drv-name (operating-system-derivation os) #f)
- (non-grafted (operating-system-derivation os))
+ (non-grafted os)
(libc-utf8-locales-for-target)
guile-3.0
- (make-non-grafted-package
- (list
- guile-3.0
- ;; `(,guile-3.0 "debug")
- (libc-utf8-locales-for-target)
- texinfo))))
+ ;; (map
+ ;; non-grafted
+ ;; (list
+ ;; guile-3.0
+ ;; (libc-utf8-locales-for-target)
+ ;; texinfo))
+ ))
(operating-system-user-services os)))))
-(operating-system-with-build-inputs %ruther/base-laptop-os)
+;; (operating-system-with-build-inputs %ruther/base-laptop-os)
%ruther/base-laptop-os
M => +1 -1
@@ 1,1 1,1 @@
font=Hack:size=12
\ No newline at end of file
font=Comic Shanns Mono:size=14
\ No newline at end of file
M home/dotfiles/waybar/config.jsonc => home/dotfiles/waybar/config.jsonc +26 -0
@@ 16,6 16,7 @@
"modules-center": [
],
"modules-right": [
+ "custom/dnd",
"idle_inhibitor",
"pulseaudio",
"network",
@@ 51,6 52,18 @@
"tooltip": true,
"tooltip-format": "{app}: {title}"
},
+ "custom/dnd": {
+ "exec": "if makoctl mode | grep -qx do-not-disturb; then echo '{\"alt\":\"on\",\"class\":\"on\",\"tooltip\":\"Do not disturb: on\"}'; else echo '{\"alt\":\"off\",\"class\":\"off\",\"tooltip\":\"Do not disturb: off\"}'; fi",
+ "return-type": "json",
+ "format": "{icon}",
+ "format-icons": {
+ "on": "",
+ "off": ""
+ },
+ "on-click": "makoctl mode -t do-not-disturb; pkill -RTMIN+8 waybar",
+ "signal": 8,
+ "interval": 60
+ },
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
@@ 155,6 168,7 @@
"modules-center": [
],
"modules-right": [
+ "custom/dnd",
"idle_inhibitor",
"pulseaudio",
"network",
@@ 191,6 205,18 @@
"tooltip": true,
"tooltip-format": "{app}: {title}"
},
+ "custom/dnd": {
+ "exec": "if makoctl mode | grep -qx do-not-disturb; then echo '{\"alt\":\"on\",\"class\":\"on\",\"tooltip\":\"Do not disturb: on\"}'; else echo '{\"alt\":\"off\",\"class\":\"off\",\"tooltip\":\"Do not disturb: off\"}'; fi",
+ "return-type": "json",
+ "format": "{icon}",
+ "format-icons": {
+ "on": "",
+ "off": ""
+ },
+ "on-click": "makoctl mode -t do-not-disturb; pkill -RTMIN+8 waybar",
+ "signal": 8,
+ "interval": 60
+ },
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
M home/dotfiles/waybar/style.css => home/dotfiles/waybar/style.css +5 -0
@@ 84,6 84,7 @@ button:hover {
#custom-media,
#tray,
#mode,
+#custom-dnd,
#idle_inhibitor,
#scratchpad,
#power-profiles-daemon,
@@ 135,6 136,10 @@ button:hover {
padding-right: 15px;
}
+#custom-dnd.on {
+ color: #f53c3c;
+}
+
label:focus {
background-color: #000000;
}
M home/home-configuration.scm => home/home-configuration.scm +2 -18
@@ 119,21 119,6 @@
(find-files source "\\.(otf|otc)$"))
#t))))))))
-(define (apply-patches pkg patches)
- (let ((src (package-source pkg))
- (source-patches
- (if (list? patches)
- patches
- (list patches))))
- (package
- (inherit pkg)
- (source
- (origin
- (inherit src)
- (patches
- (append source-patches
- (origin-patches src))))))))
-
(home-environment
(packages
(append
@@ 149,8 134,7 @@
dwm
offlineimap
- (apply-patches msmtp
- (local-file "./patches/msmtp-from-utf8-encoding.patch"))
+ msmtp
(emacs-for-tty)
(emacs-packages))
(specifications->packages
@@ 263,7 247,7 @@ $XDG_DATA_DIRS")
(service home-gtk-service-type
(let ((gtk-theme (make-graphite-gtk-theme #:theme "orange" #:color "dark"))
(icon-theme (make-tela-circle-icon-theme #:variant "orange"))
- (cursor-theme (make-catppuccin-cursors #:flavor "frappe" #:accent "sapphire")))
+ (cursor-theme (make-catppuccin-cursors #:flavor "latte" #:accent "maroon")))
(home-gtk-configuration
(gtk-theme
(gtk-theme-configuration
M home/modules/ruther/home/dwl/config.h => home/modules/ruther/home/dwl/config.h +46 -0
@@ 287,3 287,49 @@ static const Button buttons[] = {
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
};
+
+bool applycustomrules(const char *appid, const char *title, Rule *r)
+{
+ static int opened_librewolf = 0; // appid librewolf
+ static int opened_firefox = 0; // appid Firefox
+ static int opened_vesktop = 0; // appid vesktop
+ static int opened_element = 0; // appid Element
+
+ if (strstr(appid, "librewolf")) {
+ if (opened_librewolf < 4) {
+ r->tags = 1 << (opened_librewolf / 2);
+ r->allow_activation = 1;
+ opened_librewolf++;
+ return true;
+ }
+ }
+
+ if (strstr(appid, "Firefox")) {
+ if (opened_firefox < 2) {
+ r->tags = 1 << 7;
+ r->allow_activation = 1;
+ opened_firefox++;
+ return true;
+ }
+ }
+
+ if (strstr(appid, "Element")) {
+ if (opened_element < 2) {
+ r->tags = 1 << 8;
+ r->allow_activation = 1;
+ opened_element++;
+ return true;
+ }
+ }
+
+ if (strstr(appid, "vesktop")) {
+ if (opened_vesktop < 2) {
+ r->tags = 1 << 8;
+ r->allow_activation = 1;
+ opened_vesktop++;
+ return true;
+ }
+ }
+
+ return false;
+}
M home/modules/ruther/home/dwl/scripts.scm => home/modules/ruther/home/dwl/scripts.scm +6 -1
@@ 76,7 76,12 @@
"start"
"wlr-services"
(getenv "WAYLAND_DISPLAY")
- (getenv "DISPLAY"))))
+ (getenv "DISPLAY"))
+
+ (system "librewolf &")
+ (system "firefox &")
+ (system "element-desktop &")
+ (system "dev.vencord.Vesktop &")))
(define (start-dwl-gexp dwl waybar)
#~(begin
M home/modules/ruther/home/dwl/wm.scm => home/modules/ruther/home/dwl/wm.scm +3 -3
@@ 120,14 120,14 @@
(method git-fetch)
(uri (git-reference
(url "https://git.ditigal.xyz/~ruther/dwl")
- (commit "2daeeb4ffd1b7b382b80976a14f0ae5f23b920b9")))
+ (commit "c5333e44d94f9d3cf439ac7e257d64f3f3014cfb")))
(file-name (git-file-name name "0.8-dev"))
(sha256
- (base32 "1r5k6vzmgwwlwd3giym1fy3y633i770a838fbzrc41afnbwrzz8s"))))
+ (base32 "1cbhan45jznpgwgrn9xab5605i8l4ldrlswwrj5a5pg7w4a1y2cv"))))
(inputs
(modify-inputs (package-inputs base)
(append foot)
- (append rofi-wayland)
+ (append rofi)
(append swaylock)
(append mew)
(append dmenu-wl)
D home/patches/msmtp-from-utf8-encoding.patch => home/patches/msmtp-from-utf8-encoding.patch +0 -119
@@ 1,119 0,0 @@
-From d4e93269f280a57863f55f30a910afabaf424c24 Mon Sep 17 00:00:00 2001
-From: Martin Lambers <marlam@marlam.de>
-Date: Sat, 28 Sep 2024 13:13:37 +0200
-Subject: [PATCH] Properly encode non-ASCII strings in the From header
-
-This fixes Github issue #162.
----
- src/msmtp.c | 4 +++-
- src/tools.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- src/tools.h | 8 ++++++++
- 3 files changed, 67 insertions(+), 1 deletion(-)
-
-diff --git a/src/msmtp.c b/src/msmtp.c
-index 95297a6..75a4a29 100644
---- a/src/msmtp.c
-+++ b/src/msmtp.c
-@@ -4187,8 +4187,10 @@ int main(int argc, char *argv[])
- {
- if (account->from_full_name)
- {
-+ char *enc_name = encode_for_header(account->from_full_name);
- fprintf(prepend_header_tmpfile, "From: %s <%s>\n",
-- account->from_full_name, account->from);
-+ enc_name, account->from);
-+ free(enc_name);
- }
- else
- {
-diff --git a/src/tools.c b/src/tools.c
-index d029f24..11718d3 100644
---- a/src/tools.c
-+++ b/src/tools.c
-@@ -50,9 +50,11 @@
- #include <unistd.h>
- #ifdef ENABLE_NLS
- # include <locale.h>
-+# include <langinfo.h>
- #endif
-
- #include "xalloc.h"
-+#include "base64.h"
- #include "tools.h"
-
-
-@@ -907,3 +909,57 @@ int check_hostname_matches_domain(const char *hostname, const char *domain)
- return (hostname[hostname_len - 1 - domain_len] == '.'
- && strcasecmp(hostname + (hostname_len - domain_len), domain) == 0) ? 1 : 0;
- }
-+
-+
-+/*
-+ * encode_for_header()
-+ *
-+ * see tools.h
-+ */
-+
-+char *encode_for_header(const char *s)
-+{
-+ int needsEncoding = 0;
-+ for (int i = 0; s[i]; i++)
-+ {
-+ if (s[i] < 32 || s[i] >= 127)
-+ {
-+ needsEncoding = 1;
-+ break;
-+ }
-+ }
-+ if (needsEncoding)
-+ {
-+ /* create a string of the form "=?ENCODING?B?BASE64STRING?=" */
-+ size_t s_len = strlen(s);
-+ size_t b64_s_len = BASE64_LENGTH(s_len);
-+ char* encoding = xstrdup(
-+#ifdef ENABLE_NLS
-+ nl_langinfo(CODESET)
-+#else
-+ "UTF-8";
-+#endif
-+ );
-+ size_t e_len = strlen(encoding);
-+ size_t enc_len = 2 + e_len + 3 + b64_s_len + 3;
-+ char *enc = xmalloc(enc_len + 1);
-+ size_t i = 0;
-+ enc[i++] = '=';
-+ enc[i++] = '?';
-+ for (size_t j = 0; j < e_len; j++)
-+ {
-+ enc[i++] = tolower(encoding[j]);
-+ }
-+ free(encoding);
-+ enc[i++] = '?';
-+ enc[i++] = 'B';
-+ enc[i++] = '?';
-+ base64_encode(s, s_len, enc + i, enc_len - i + 1);
-+ strcat(enc, "?=");
-+ return enc;
-+ }
-+ else
-+ {
-+ return xstrdup(s);
-+ }
-+}
-diff --git a/src/tools.h b/src/tools.h
-index 86ba9ff..ebdeb73 100644
---- a/src/tools.h
-+++ b/src/tools.h
-@@ -259,4 +259,12 @@ void split_mail_address(const char *address, char **local_part, char **domain_pa
- */
- int check_hostname_matches_domain(const char *hostname, const char *domain);
-
-+/*
-+ * encode_for_header()
-+ *
-+ * Encode a string so that it can be used in a mail header.
-+ * The result is allocated and needs to be freed.
-+ */
-+char *encode_for_header(const char *s);
-+
- #endif
M home/patches/offlineimap3.patch => home/patches/offlineimap3.patch +167 -11
@@ 1,11 1,167 @@
---- a/offlineimap/localeval.py 2025-05-04 12:19:37.739860684 +0200
-+++ b/offlineimap/localeval.py 2025-05-04 12:26:07.838113251 +0200
-@@ -26,6 +26,8 @@
- self.namespace = {}
-
- if path is not None:
-+ import importlib.machinery
-+
- # FIXME: limit opening files owned by current user with rights set
- # to fixed mode 644.
- foo = open(path, 'r')
+From 1c4f9b4f05de575cd99ac5bad68c6e0bbad25374 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rodolfo=20Garc=C3=ADa=20Pe=C3=B1as=20=28kix=29?=
+ <kix@kix.es>
+Date: Wed, 13 May 2026 18:35:54 +0200
+Subject: [PATCH] Enhance STARTTLS handling with fallback for non-standard IMAP
+ servers
+
+- Implement tolerance for non-standard IMAP servers that do not provide reliable CAPABILITY after STARTTLS.
+- Introduce configuration option 'allow_nonstandard_capabilities' to enable fallback using pre-TLS capabilities.
+---
+ offlineimap/imapserver.py | 110 +++++++++++++++++++++++++++------
+ offlineimap/repository/IMAP.py | 7 +++
+ 2 files changed, 98 insertions(+), 19 deletions(-)
+
+diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py
+index fd866867..b29b5d6c 100644
+--- a/offlineimap/imapserver.py
++++ b/offlineimap/imapserver.py
+@@ -363,32 +363,95 @@ def __gsshandler(self, token):
+ return None
+
+ def __start_tls(self, imapobj):
+- if 'STARTTLS' in imapobj.capabilities and not self.usessl:
+- self.ui.debug('imap', 'Using STARTTLS connection')
+- # imaplib2.starttls() unconditionally calls _get_capabilities() right
+- # after the TLS handshake (before setting _tls_established=True).
+- # Servers like Protonmail Bridge do not respond to CAPABILITY at
+- # that stage, causing a 60-second hang. We bypass it by temporarily
+- # substituting a no-op; imaplib2 still sets _tls_established=True
+- # normally, and acquireconnection() already guards its own
+- # post-login CAPABILITY refresh against that flag (see below).
+- _orig_get_cap = imapobj._get_capabilities
+- imapobj._get_capabilities = lambda: None
++ """Upgrade connection to TLS if STARTTLS is configured.
++
++ - Uses pre-TLS capabilities only to decide whether to perform STARTTLS.
++ - After STARTTLS, forces a CAPABILITY command and replaces internal
++ capabilities with the post-TLS response.
++ - If no reliable post-TLS CAPABILITY is available:
++ - In strict mode (allow_nonstandard_capabilities = no): abort.
++ - In tolerant mode (allow_nonstandard_capabilities = yes):
++ reuse pre-TLS capabilities, removing LOGINDISABLED.
++ """
++
++ # If the repository does not want STARTTLS, do nothing.
++ if not self.starttls or self.usessl:
++ return
++
++ # Pre-TLS capabilities (from initial banner / CAPABILITY).
++ caps_pre = set(getattr(imapobj, '_offlineimap_capabilities_pre_tls',
++ getattr(imapobj, 'capabilities', [])))
++
++ # If the server does not advertise STARTTLS, respect that.
++ if 'STARTTLS' not in caps_pre:
++ return
++
++ # Execute STARTTLS.
++ self.ui.debug('imap', 'Using STARTTLS connection')
++
++ # Disable _get_capabilities() during starttls() to prevent imaplib2
++ # from issuing CAPABILITY before we can do it ourselves.
++ _orig_get_cap = imapobj._get_capabilities
++ imapobj._get_capabilities = lambda: None
++ try:
+ try:
+ imapobj.starttls()
+ except imapobj.error as e:
+ err = "Failed to start TLS connection: %s" % str(e)
+ raise OfflineImapError(err, OfflineImapError.ERROR.REPO,
+ exc_info()[2])
+- finally:
+- # Always restore the original method, even on success.
+- imapobj._get_capabilities = _orig_get_cap
+- elif self.starttls and not self.usessl:
++ finally:
++ # Always restore the original method, even on error.
++ imapobj._get_capabilities = _orig_get_cap
++
++ # At this point, the socket is encrypted. Now we must refresh CAPABILITY.
++ caps_post = None
++ try:
++ typ, data = imapobj.capability()
++ if typ == 'OK' and data:
++ # data is a list of bytes, e.g. [b'IMAP4rev1 IDLE AUTH=PLAIN']
++ line = data[0]
++ if isinstance(line, bytes):
++ line = line.decode('ascii', 'ignore')
++ caps_post = set(line.upper().split())
++ except Exception:
++ caps_post = None
++
++ if caps_post is not None:
++ # Standard path: completely replace capabilities
++ imapobj.capabilities = caps_post
++ imapobj._offlineimap_capabilities_post_tls = caps_post
++ return
++
++ # If we reach here, we do not have reliable post-TLS capabilities.
++ # Decide based on repository configuration.
++ allow_nonstandard = getattr(self.repos,
++ 'allow_nonstandard_capabilities', False)
++
++ if not allow_nonstandard:
++ # Strict mode: abort with clear error.
+ raise OfflineImapError(
+- "STARTTLS requested but server does not advertise STARTTLS capability. "
+- "Aborting to prevent sending password in plaintext (possible MITM attack). "
+- "If you REALLY want an insecure connection, set 'starttls = no'.",
+- OfflineImapError.ERROR.REPO)
++ "Server did not provide valid CAPABILITY after STARTTLS; "
++ "set 'allow_nonstandard_capabilities = yes' in repository "
++ "configuration to enable a non-standard fallback.",
++ OfflineImapError.ERROR.REPO
++ )
++
++ # Tolerant mode: best-effort using caps_pre.
++ caps_fallback = set(caps_pre)
++ if 'LOGINDISABLED' in caps_fallback:
++ # We assume that after STARTTLS, LOGINDISABLED no longer applies,
++ # so we remove it to allow LOGIN/AUTH configured by the user.
++ caps_fallback.remove('LOGINDISABLED')
++
++ imapobj.capabilities = caps_fallback
++ imapobj._offlineimap_capabilities_post_tls = caps_fallback
++
++ self.ui.warn(
++ "Server did not provide CAPABILITY after STARTTLS; "
++ "falling back to pre-TLS capabilities without LOGINDISABLED "
++ "due to allow_nonstandard_capabilities = yes."
++ )
+
+ # All __authn_* procedures are helpers that do authentication.
+ # They are class methods that take one parameter, IMAP object.
+@@ -605,6 +668,15 @@ def acquireconnection(self):
+ self.lastowner[imapobj] = curThread.ident
+ self.connectionlock.release()
+
++ # Store the pre-TLS capabilities (from banner and initial CAPABILITY).
++ # This will be used only to decide STARTTLS and, in case of non-standard
++ # fallback, to reconstruct an approximate post-TLS capability list.
++ try:
++ caps_pre = set(getattr(imapobj, 'capabilities', []))
++ except Exception:
++ caps_pre = set()
++ imapobj._offlineimap_capabilities_pre_tls = caps_pre
++
+ # Verify that the connection is still alive before returning it
+ # to the caller. If not, clean up and recursively call
+ # acquireconnection() to get a new one.
+diff --git a/offlineimap/repository/IMAP.py b/offlineimap/repository/IMAP.py
+index b1afe861..db64dae1 100644
+--- a/offlineimap/repository/IMAP.py
++++ b/offlineimap/repository/IMAP.py
+@@ -38,6 +38,13 @@ def __init__(self, reposname, account):
+ self.idlefolders = None
+ BaseRepository.__init__(self, reposname, account)
+ # self.ui is being set by the BaseRepository
++
++ # Allow tolerance for non-standard IMAP servers that do not provide
++ # reliable CAPABILITY after STARTTLS. Default is strict (False).
++ # If set to True, heuristics using pre-TLS capabilities are applied
++ # as a fallback.
++ self.allow_nonstandard_capabilities = self.getconfboolean(
++ 'allow_nonstandard_capabilities', False)
+ self._host = None
+ # Must be set before calling imapserver.IMAPServer(self)
+ self.oauth2_request_url = None
M isos/simple.scm => isos/simple.scm +1 -1
@@ 77,7 77,7 @@
(package-version guix))))
- (kernel linux-6.13)
+ (kernel linux-lts)
(firmware (cons* linux-firmware
%base-firmware))
A modules/ruther/services/auto-login.scm => modules/ruther/services/auto-login.scm +49 -0
@@ 0,0 1,49 @@
+(define-module (ruther services auto-login)
+ #:use-module (guix gexp)
+ #:use-module (gnu packages admin)
+ #:use-module (gnu packages base)
+ #:export (make-auto-login-program))
+
+(define* (make-auto-login-program #:key (users '()))
+ (program-file
+ "auto-login"
+ #~(begin
+ (define users (list #$@users))
+ (define marker "/tmp/.auto-login-done")
+ (define stty-bin #$(file-append coreutils "/bin/stty"))
+
+ (define (show-menu!)
+ (display "\nAuto-login — choose account:\n")
+ (let loop ((us users) (i 0))
+ (when (pair? us)
+ (format #t " ~a) ~a\n" (integer->char (+ i (char->integer #\a))) (car us))
+ (loop (cdr us) (+ i 1))))
+ (display "> "))
+
+ (define (read-key)
+ (dynamic-wind
+ (lambda () (system* stty-bin "-echo" "cbreak"))
+ (lambda () (read-char))
+ (lambda () (system* stty-bin "echo" "-cbreak"))))
+
+ (define (read-choice)
+ (show-menu!)
+ (let* ((ch (read-key))
+ (idx (- (char->integer ch) (char->integer #\a))))
+ (newline)
+ (if (and (>= idx 0) (< idx (length users)))
+ (list-ref users idx)
+ (begin
+ (display "Invalid choice, try again.\n")
+ (read-choice)))))
+
+ (let ((login-bin #$(file-append shadow "/bin/login"))
+ (args (filter (lambda (a) (not (or (string=? a "-f")
+ (string=? a "auto"))))
+ (cdr (command-line))))) ; strip -f and dummy username injected by mingetty
+ (if (file-exists? marker)
+ (apply execlp login-bin login-bin args)
+ (let ((user (read-choice)))
+ (call-with-output-file marker
+ (lambda (p) (display (getpid) p)))
+ (apply execlp login-bin login-bin "-f" user args)))))))
A modules/ruther/services/nix.scm => modules/ruther/services/nix.scm +58 -0
@@ 0,0 1,58 @@
+;; Custom nix-daemon service that raises its NOFILE rlimit.
+;;
+;; The stock (gnu services nix) nix-daemon is started by shepherd with the
+;; default 1024/4096 open-files rlimit. Build processes run as @nixbld are
+;; spawned as children of the daemon, so they inherit that limit — PAM limits
+;; for @nixbld are ineffective because nixbld users never log in.
+;;
+;; This module re-exports a service type that inherits from nix-service-type
+;; but replaces its shepherd-root-service-type extension with one that passes
+;; #:resource-limits to make-forkexec-constructor.
+
+(define-module (ruther services nix)
+ #:use-module (srfi srfi-1)
+ #:use-module (guix gexp)
+ #:use-module (gnu services)
+ #:use-module (gnu services nix)
+ #:use-module (gnu services shepherd)
+ #:export (nix-service-type/raised-nofile))
+
+;; The nix-configuration-* accessors are not exported from (gnu services nix),
+;; so reach in with @@.
+(define nix-configuration-package
+ (@@ (gnu services nix) nix-configuration-package))
+(define nix-configuration-build-directory
+ (@@ (gnu services nix) nix-configuration-build-directory))
+(define nix-configuration-extra-options
+ (@@ (gnu services nix) nix-configuration-extra-options))
+
+(define (nix-shepherd-service/raised-nofile config)
+ (let ((package (nix-configuration-package config))
+ (build-directory (nix-configuration-build-directory config))
+ (extra-options (nix-configuration-extra-options config)))
+ (list
+ (shepherd-service
+ (provision '(nix-daemon))
+ (documentation "Run nix-daemon with a raised NOFILE rlimit.")
+ (requirement '(user-processes file-system-/nix/store))
+ (start #~(make-forkexec-constructor
+ (list (string-append #$package "/bin/nix-daemon")
+ #$@extra-options)
+ #:environment-variables
+ (list (string-append "TMPDIR=" #$build-directory)
+ "PATH=/run/current-system/profile/bin")
+ #:resource-limits
+ '((nofile 1048576 1048576))))
+ (respawn? #f)
+ (stop #~(make-kill-destructor))))))
+
+(define nix-service-type/raised-nofile
+ (service-type
+ (inherit nix-service-type)
+ (extensions
+ (cons (service-extension shepherd-root-service-type
+ nix-shepherd-service/raised-nofile)
+ (filter (lambda (ext)
+ (not (eq? (service-extension-target ext)
+ shepherd-root-service-type)))
+ (service-type-extensions nix-service-type))))))
A udev/51-android.rules => udev/51-android.rules +1 -0
@@ 0,0 1,1 @@
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="4ee1", MODE="0666", TAG+="uaccess", SYMLINK+="android%n"<
\ No newline at end of file