GNU bug report logs - #76019
31.0.50; ERC 5.7: A 'settings' module for locally scoped configuration

Previous Next

Package: emacs;

Reported by: "J.P." <jp <at> neverwas.me>

Date: Sun, 2 Feb 2025 23:39:01 UTC

Severity: wishlist

Tags: patch

Found in version 31.0.50

To reply to this bug, email your comments to 76019 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to emacs-erc <at> gnu.org, bug-gnu-emacs <at> gnu.org:
bug#76019; Package emacs. (Sun, 02 Feb 2025 23:39:01 GMT) Full text and rfc822 format available.

Acknowledgement sent to "J.P." <jp <at> neverwas.me>:
New bug report received and forwarded. Copy sent to emacs-erc <at> gnu.org, bug-gnu-emacs <at> gnu.org. (Sun, 02 Feb 2025 23:39:01 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: "J.P." <jp <at> neverwas.me>
To: bug-gnu-emacs <at> gnu.org
Subject: 31.0.50; ERC 5.7: A 'settings' module for locally scoped configuration
Date: Sun, 02 Feb 2025 15:33:17 -0800
[Message part 1 (text/plain, inline)]
Tags: patch
Severity: wishlist

The name `erc-settings' likely no longer rings a bell, even for longtime
ERC users. It represents an idea flirted with decades ago but sadly
never brought to fruition. Still, you need only look near the bottom of
lisp/erc/erc-networks.el for traces of its promise. This proposal aims
to revive that abandoned pursuit, which remains as relevant as ever.

Indeed, among the more common gripes directed at ERC in recent years has
been the lack of granular control over its many options [0]. This is
often voiced as a desire not only for per-session precision but for
per-buffer control as well. This bug presents an attempt to meet these
requirements in a somewhat crude but ultimately functional way. What
follows is the latest draft of its documentation:

  File: erc.info,  Node: Settings,  Up: Modules

  4.1 Settings
  ============

  This global module lets you apply ERC options on a per-buffer basis, as
  local variable bindings (*note (elisp)Buffer-Local Variables::).  It
  consists of a single “meta option”:

   -- User Option: erc-settings
       An alist where each key is a “match condition” and each value a
       list of bindings that loosely resembles a ‘let’-style VARLIST.  The
       first element of each binding is the variable of a user option and
       the second an arbitrary sexp assigned to it locally in all matching
       buffers.  You can tell ERC to evaluate a given sexp as a Lisp form
       before assigning it by including a trailing third element: the
       “modifier flag” ‘:eval’.

       A match condition specifies when and whether ERC should apply each
       group of bindings.  These resemble ‘buffer-match-p’ conditions,
       with two major differences.  The first is that predicate conditions
       don't take any arguments.  Instead, ERC runs them with the
       candidate buffer current.  The second difference is that the
       assortment of associative cons-cell conditions is completely new.
       Gone are ‘major-mode’, ‘category’, etc.  In their place, ERC offers
       the following:

          • ‘(network . ‘<symbol>’)’
          • ‘(id . ‘<symbol>’)’
          • ‘(name . ‘<string>’)’
          • ‘(target . ‘<string or nil>’)’

       The associated ‘cdr’ values for the ‘network’ and ‘id’ conditions
       are symbols identifying the current IRC network and the “network
       context”, respectively.  When first connecting, a ‘network’
       condition is always ‘nil’, but an ‘id’ condition can be non-‘nil’
       if you supply a matching ID argument to an entry-point command,
       like ‘erc-tls’ (*note Network Identifier::).

       Additionally, ERC also recognizes ‘buffer-match-p’'s boolean
       operations and constants:

          • ‘(and ‘<condition...>’)’
          • ‘(or ‘<condition...>’)’
          • ‘(not ‘<condition>’)’
          • ‘t’
          • ‘nil’

       Also valid are regular expressions and nullary predicates:

          • ‘"<some regexp>"’
          • ‘<predicate symbol>’

  Here's a contrived ‘erc-settings’ value containing six entries, the
  first of which has two assignments:

       (((and (network . Libera.Chat)          ; buffers #emacs,
              "\\`#emacs")                     ; #emacs-foo, etc.,
         (my-own-variable 42)                  ; on Libera.Chat only
         (erc-foo ""))

        ((or (target . "#chan")                ; buffers #chan, bob,
             (target . "bob"))                 ; chan <at> Libera.Chat,
         (erc-foo (erc-current-nick) :eval))   ; bob <at> OFTC, etc.

        (erc-open-server-buffer-p (erc-bar 1)) ; connected server buffers
        (erc-query-buffer-p (erc-bar 2))       ; query buffers only
        (erc-channel-buffer-p (erc-bar 3))     ; channel buffers only
        (erc-target (erc-bar 4))               ; query or channel buffers
        (t (erc-bar 5)))                       ; any `erc-mode' buffer

  Unfortunately, predicates too dissimilar from those shown above may not
  work in all matching contexts due to the interaction between this module
  and ERC's rather convoluted major-mode setup.  While the only way to
  know for sure is to try them, selecting them becomes much easier if you
  can gain a sense for when exactly ‘settings’ attempts to create
  bindings:

     • In a server buffer, binding happens
         1. before ERC enables any modules or sets any local variables
         2. after establishing a logical IRC connection and learning what
            network it's connected to

     • In a target buffer, binding happens
         1. before enabling any modules, but only if you're overriding
            ‘erc-modules’, and only then, for that option alone
         2. after ERC has set most of its default local variables and run
            global-module setup but before running major-mode hooks or
            local-module setup

     The main downside of this staggered approach is that ‘settings’ skips
  any bindings for variables that already have a local binding rather than
  do the intuitive thing and simply clobber them.  The reason for this is
  to retain a consistent state between a global module's minor mode setup
  and any local-module setup or major-mode hooks.  They must all witness
  the same value for the same variable.

     Revisiting the quasi-example above with this precedence quirk in
  mind, notice that the made-up variable ‘erc-bar’ will be ‘2’ in query
  buffers, ‘3’ in channel buffers, and ‘5’ in server buffers.  It's never
  ‘1’ because the first binding opportunity occurs before connecting, when
  ‘erc-open-server-buffer-p’ returns ‘nil’.  It's likewise never ‘4’
  because that binding appears lower in the list than those for ‘2’ and
  ‘3’.  For more on this behavior, see the very last example below.

     When it comes to binding the option ‘erc-modules’, ‘settings’ must
  make special accommodations.  Getting it right may take some trial and
  error, and it's only guaranteed to work for local modules because most
  global ones share state among all sessions.  However, it's fine to
  include global modules in an ‘erc-modules’ binding as long as they also
  appear in the ‘default-value’.  To set ‘erc-modules’ for a specific
  server buffer, specify an entry like

       ("[.]libera[.]chat:"
        (erc-modules (seq-union '(sasl keep-place-indicator) erc-modules)
                     :eval)
        (erc-sasl-user :nick))

  Here, the match condition is a regexp matching a dialed TCP address
  because server buffers typically have these as temporary names while
  connecting.  As mentioned, ERC later renames them to reflect a
  discovered network, after which ‘settings’ binds any matching unbound
  options.

     A session's target buffers normally share the ‘erc-modules’ value
  bound locally in their server buffer.  To specify a separate, overriding
  set of modules for certain target buffers, use a condition that only
  applies to them:

       ((and (network . Libera.Chat) erc-channel-buffer-p)
        (erc-modules (seq-union '(fill-wrap) erc-modules) :eval))

  This is often unnecessary because local modules that only operate in one
  kind of buffer tend to disable themselves elsewhere.  And some, like
  ‘keep-place-indicator’, offer an option to restrict activation based on
  buffer type.

  4.1.1 Settings Examples
  -----------------------

  A typical setup might include configuration for two networks, one that
  uses SASL to authenticate and another that uses a server password.

       (setopt erc-modules
               `(settings ,@erc-modules)

               erc-settings
               ;; Pre-connect and server buffer config for ‘Libera.Chat’.
               '(("libera\\.chat:"
                  (erc-prompt "Libera>")
                  (erc-autojoin-channels-alist ((Libera.Chat "##jrh")))
                  (erc-header-line-format "%n on %S (%m, %l)")
                  (erc-sasl-user :nick)
                  (erc-modules `(sasl ,@erc-modules) :eval))

                 ;; Channel buffer config for ‘Libera.Chat’
                 ((and (network . Libera.Chat) erc-channel-buffer-p)
                  (erc-modules `(keep-place-indicator ,@erc-modules) :eval)
                  (erc-prompt erc-prompt-format)
                  (erc-prompt-format "%c%b>")
                  (erc-header-line-format "%t: %o"))

                 ;; Query buffer configuration for any network.
                 (erc-query-buffer-p
                  (erc-prompt erc-prompt-format)
                  (erc-prompt-format "%S>")
                  (erc-header-line-format nil))

                 ;; Pre-connect and server-buffer config for ‘OFTC’.
                 ("oftc.net:"
                  (erc-prompt "OFTC!")
                  (erc-modules `(nicks ,@erc-modules) :eval))))

     Note that the pre-connection config described in the last entry can't
  use the “global module” ‘services’ because it's incompatible with the
  “local module” ‘sasl’.  In this scenario, instead of a server password,
  the ‘OFTC’ connection could alternatively use “CertFP” via auth-source
  (see next example).

  4.1.1.1 ID-based
  ................

  New users coming from traditional IRC clients often express a desire to
  store connection details alongside other per-network or per-connection
  configuration.  Although ERC was designed to keep these concerns
  separate, the ‘settings’ module can emulate that experience to some
  degree.

       (setopt erc-modules
               `(settings ,@erc-modules)

               erc-settings
               ;; Connection details common to both ‘Libera.Chat’ IDs.
               '(((and (or (id . lib-jrh) (id . lib-jrbot))
                       (not erc-server-process-alive))
                  (erc-server "irc.libera.chat")
                  (erc-port 6697)
                  (erc-modules `(sasl ,@erc-modules) :eval))

                 ;; Connection details for account ‘jrh’.
                 ((and (id . lib-jrh) (not erc-server-process-alive))
                  (erc-nick "jrh")
                  (erc-user-full-name "J. Random Hacker")
                  (erc-email-userid "jrh")
                  (erc-autojoin-channels-alist ((lib-jrh "##jrh"))))

                 ;; Connection details for account ‘jrbot’.
                 ((and (id . lib-jrbot) (not erc-server-process-alive))
                  (erc-nick "jrbot")
                  (erc-email-userid "jrbot")
                  (erc-user-full-name "J.R. Bot (jrh's bot)")
                  (erc-sasl-auth-source-function erc-auth-source-function)
                  (erc-autojoin-channels-alist ((lib-jrbot "##jrh" "##jrbot"))))

                 ;; Non-connection opts for both ‘Libera.Chat’ sessions.
                 ((and (network . Libera.Chat) erc-open-server-buffer-p)
                  (erc-prompt "libera>")
                  (erc-header-line-format "%n on %S (%m, %l)"))
                 ((and (network . Libera.Chat) erc-channel-buffer-p)
                  (erc-modules `(keep-place-indicator ,@erc-modules) :eval)
                  (erc-prompt erc-prompt-format)
                  (erc-prompt-format "%c%b>")
                  (erc-header-line-format "%t: %o"))

                 ;; Server details for ‘OFTC’.
                 ((and (id . oftc) (target . nil))
                  (erc-server "irc.oftc.net")
                  (erc-port 6697)
                  (erc-nick "jrh")
                  (erc-email-userid "jrh")
                  (erc-user-full-name "J. Random Hacker")
                  (erc-client-certificate t)
                  (erc-modules `(services-regain ,@erc-modules) :eval)
                  (erc-prompt "jrh <at> OFTC!"))))

       (defun my-erc-up (id)
         "Connect to preconfigured session identified by ID."
         (interactive "SNet id: ")
         (erc-tls :server nil
                  :port nil
                  :nick nil
                  :user nil
                  :password nil
                  :full-name nil
                  :id network-id))

  With a setup like the above, you can connect explicitly to a predefined
  session by supplying an identifying symbol, like ‘lib-jrh’, along with
  the ID keyword parameter to the entry-point command ‘erc-tls’.  The main
  gotcha when using these identifiers is that a regexp targeting a dialed
  TCP address, like ‘"\\`irc[.]libera[.]chat:6697\\'"’, won't work for
  conditions like the first one above because server buffers receive
  permanent names immediately upon creation, long before connecting.
  Instead, you'll want to specify a chosen identifier via the ‘(id .
  <symbol>)’ pattern and likely qualify it with another subcondition, like
  ‘(not erc-server-process-alive)’, to ensure that the ‘erc-modules’
  binding only matches the server buffer and not any target buffers.
  Equivalent qualifying subconditions would be ‘(not erc-target)’ and
  ‘(target . nil)’.

     Regarding authentication, notice that the ‘lib-jrbot’ connection
  retrieves its SASL credentials, which might be a client certificate, via
  auth-source, while session ‘lib-jrh’ prompts you interactively for a
  password.  (*Note SASL in ERC: SASL.) The ‘oftc’ connection also uses
  auth-source to supply its credentials, this time for non-SASL
  client-cert (“CertFP”) authentication.  Lastly, in the scenario above, a
  user would need to run ‘M-x my-erc-up <RET>’ instead of ‘M-x erc <RET>’
  when connecting to IRC. For convenience, ERC provides a similar command:

   -- Function: erc-settings-connect-by-id network-id
       Prompt the user and provide completion for some ‘(id . <symbol>)’
       appearing in their ‘erc-settings’, and specify it as the argument
       to the ID keyword parameter when invoking ‘erc-tls’.

     With both traditional and ID-based setups, it's often more convenient
  to define less exclusive, more "overlapping" match conditions:

       (use-package erc-settings
         :custom
         (erc-settings
          '(((not erc-server-process-alive) ; common to all servers
             (erc-nick "jrh")
             (erc-port 6697)
             (erc-email-userid "jrh")
             (erc-user-full-name "J. Random Hacker"))

            (erc-channel-buffer-p ; all channels
             (erc-modules `(keep-place-indicator ,@erc-modules) :eval))

            ((id . id-libera) ; Libera.Chat only, including targets
             (erc-server "irc.libera.chat")
             (erc-sasl-password "changeme")
             (erc-modules `(sasl ,@erc-modules) :eval)
             (erc-prompt erc-prompt-format)
             (erc-autojoin-channels-alist ((id-foonet "#erc"))))

            ((id . id-oftc) ; OFTC only, including targets
             (erc-server "irc.oftc.net")
             (erc-modules `(fill-wrap ,@erc-modules) :eval)
             (erc-autojoin-channels-alist ((id-barnet "##jrh")))))))

     If you go this route, know that ‘settings’ will often create local
  bindings in buffers where they're not applicable.  In the above example,
  buffer ‘#erc’ on ‘Libera.Chat’ will have ‘erc-server’ and
  ‘erc-sasl-password’ bound locally for no reason.  In most cases, this is
  perfectly harmless.

     A final thing to notice about the example above is that the
  ‘erc-modules’ binding in the second group, the one with match condition
  ‘erc-channel-buffer-p’, effectively “shadow”s that same variable in all
  remaining settings affecting channel buffers.  If it instead appeared at
  the end of the list, ERC would skip its ‘erc-modules’ binding because
  the variable would already be locally bound.  But, as is, both ‘##jrh’
  on ‘OFTC’ and ‘#erc’ on ‘Libera.Chat’ activate ‘keep-place-indicator’
  but not ‘fll-wrap’.  Server buffer ‘id-oftc’ has only ‘fll-wrap’, and
  server buffer ‘id-libera’ has neither.  And, if you were to receive a
  query from ‘alice’ on ‘OFTC’, buffer ‘alice’ would only have ‘fill-wrap’
  but not ‘keep-place-indicator’ because it's a non-channel on ‘OFTC’.


Mock FAQ
========
These are just some imagined areas of concern. Any actual feedback is of
course most welcome.

Q: Why the flat alist structure for the `erc-settings' option. Wouldn't
   a shallow tree resembling dir-locals be better? Something with a top
   level that matches against a session/connection and a secondary level
   for individual constituent buffers?

A: This sounds great in theory because it's closer to how we organize
   these assignments mentally. And indeed, my earlier drafts used this
   exact shape. However, anecdotal dog-fooding has convinced me that
   this leads quickly to unwieldy configuration patterns that are overly
   verbose and difficult to predict. I'm open to being proven wrong, of
   course.

Q: Why no deep integration with Customization buffers and `use-package'?

A: Based on a cursory investigation, I believe any integration with
   `use-package' would require a change to that library itself. As for
   Customize, I think we could, in theory, couch all of ERC's existing
   user options in a widget that supports declaring a `settings' scope
   in situ. This would then somehow propagate to modify the global value
   of `erc-settings' the variable, likely on module init, perhaps with
   some sort of caching. As for the Customization buffer for
   `erc-settings' the option: I agree that it'd be ideal to find a way
   to dynamically generate typed fields for arbitrary binding values
   instead of the current and rather ugly catch-all `sexp' type. I'm
   currently looking into this.

Q: Buffer-local options are messy in that they complicate the mental
   model of how various inputs influence the state of the program.
   Moreover, it would seem to defy the main purpose of local modules,
   which is to maximize predictability and flexibility. So why not
   instead "snapshot" the state of all options of interest during local
   module setup?

A: This "snapshotting" approach seems preferable in theory but would
   also require universal buy-in from all local modules. Basically,
   local modules would henceforth be required to use some flavor of
   mandated indirection for accessing and updating persistent state. I
   fear such a hard pivot to a "managed framework" would be a tough sell
   to would-be contributors and package authors, many of whom are
   already wary of being force-fed excess magic.

Q: Why not have bindings clobber earlier ones in a "cascading" manner
   instead of the current "early bird gets the worm" basis?

A: The clobbering approach is indeed more intuitive and it would make
   sense were it not for our need to perform bindings in two stages per
   buffer type (both server and target). This has its downsides but also
   affords users multiple opportunities to match against an evolving
   landscape as more useful input arrives. As implied in the manual,
   partially at fault for this situation is a bootstrapping conundrum
   wherein the module must both influence and be influenced by its
   fellow modules (hence the annoying "meta option" designation).

Q. Isn't enabling ERC's major mode before updating modules a breaking
   change because modules lose access to the caller's buffer?

   It's a breaking change, but only superficially. As things stand, a
   module's setup code (its "enable body") can't meaningfully leverage
   this access for state transfer because it lacks a reasonable means of
   discovering the reason for its execution. We *could* make the
   original `erc-open' parameters and the calling buffer available via
   dynamic variable, but the first patch provides what I believe to be a
   tidier solution (its ERC-NEWS entry is in the _second_ patch).

Thanks for reading.


[0] https://lists.gnu.org/archive/html/bug-gnu-emacs/2023-10/msg00776.html
    https://lists.gnu.org/archive/html/bug-gnu-emacs/2024-06/msg01098.html
    https://lists.gnu.org/archive/html/bug-gnu-emacs/2022-09/msg02116.html
    https://lists.gnu.org/archive/html/emacs-erc/2022-02/msg00008.html
    https://lists.gnu.org/archive/html/emacs-erc/2021-10/msg00003.html


In GNU Emacs 31.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version
 3.24.43, cairo version 1.18.2) of 2025-01-26 built on localhost
Repository revision: 01d93d56cd469ddb45d142da948caef9f2dc1a3f
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12401004
System Description: Fedora Linux 41 (Workstation Edition)

Configured using:
 'configure --enable-check-lisp-object-type --enable-checking=yes,glyphs
 'CFLAGS=-O0 -g3'
 PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig'

Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NATIVE_COMP
NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINPUT2 XPM GTK3 ZLIB

Important settings:
  value of $LANG: en_US.UTF-8
  value of $XMODIFIERS: @im=ibus
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  minibuffer-regexp-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
None found.

Features:
(shadow sort compile comint ansi-osc ansi-color ring comp-run
comp-common mail-extr emacsbug message mailcap yank-media puny dired
dired-loaddefs rfc822 mml mml-sec epa epg rfc6068 epg-config gnus-util
text-property-search time-date mm-decode mm-bodies mm-encode mail-parse
rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045
ietf-drums mm-util mail-prsvr mail-utils erc derived auth-source eieio
eieio-core icons password-cache json map format-spec erc-backend
erc-networks easy-mmode byte-opt bytecomp byte-compile erc-common inline
cl-extra help-mode erc-compat cl-seq cl-macs gv pcase rx compat subr-x
cl-loaddefs cl-lib erc-loaddefs rmc iso-transl tooltip cconv eldoc paren
electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel
term/x-win x-win term/common-win x-dnd touch-screen tool-bar dnd fontset
image regexp-opt fringe tabulated-list replace newcomment text-mode
lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch
easymenu timer select scroll-bar mouse jit-lock font-lock syntax
font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic
indonesian philippine cham georgian utf-8-lang misc-lang vietnamese
tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
composite emoji-zwj charscript charprop case-table epa-hook
jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs
theme-loaddefs faces cus-face macroexp files window text-properties
overlay sha1 md5 base64 format env code-pages mule custom widget keymap
hashtable-print-readable backquote threads dbusbind inotify lcms2
dynamic-setting system-font-setting font-render-setting cairo gtk
x-toolkit xinput2 x multi-tty move-toolbar make-network-process
tty-child-frames native-compile emacs)

Memory information:
((conses 16 159659 10485) (symbols 48 11748 0) (strings 32 28884 4410)
 (string-bytes 1 1019143) (vectors 16 17190)
 (vector-slots 8 187670 5036) (floats 8 34 1) (intervals 56 325 0)
 (buffers 984 11))


[0001-5.7-Set-major-mode-before-updating-modules-in-erc-op.patch (text/x-patch, attachment)]
[0002-5.7-Make-erc-settings-a-module.patch (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#76019; Package emacs. (Wed, 19 Feb 2025 04:01:01 GMT) Full text and rfc822 format available.

Message #8 received at 76019 <at> debbugs.gnu.org (full text, mbox):

From: "J.P." <jp <at> neverwas.me>
To: 76019 <at> debbugs.gnu.org
Cc: emacs-erc <at> gnu.org
Subject: Re: bug#76019: 31.0.50; ERC 5.7: A 'settings' module for locally
 scoped configuration
Date: Tue, 18 Feb 2025 19:59:43 -0800
[Message part 1 (text/plain, inline)]
v2. Remove new option `erc-client-certificate'. Change parameters of
function `erc-settings--set-modules'.

[0000-v1-v2.diff (text/x-patch, attachment)]
[0001-5.7-Split-ERC-module-documentation-into-subnodes.patch (text/x-patch, attachment)]
[0002-5.7-Set-major-mode-before-updating-modules-in-erc-op.patch (text/x-patch, attachment)]
[0003-5.7-Make-erc-settings-a-module.patch (text/x-patch, attachment)]

This bug report was last modified 2 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.