Review and contributions from Thiago Kenji Okada <thiagokokada@gmail.com>. Co-authored-by: Thiago Kenji Okada <thiagokokada@gmail.com> Co-authored-by: Nicolas Berbiche <nic.berbiche@gmail.com> Co-authored-by: Sumner Evans <me@sumnerevans.com>main
parent
8278c14f5f
commit
406eeec0b9
@ -0,0 +1,368 @@ |
||||
{ config, pkgs, lib, ... }: |
||||
|
||||
with lib; |
||||
|
||||
let |
||||
cfg = config.programs.hexchat; |
||||
|
||||
channelOptions = with types; |
||||
submodule { |
||||
options = { |
||||
autoconnect = mkOption { |
||||
type = nullOr bool; |
||||
default = false; |
||||
description = "Autoconnect to network."; |
||||
}; |
||||
|
||||
connectToSelectedServerOnly = mkOption { |
||||
type = nullOr bool; |
||||
default = true; |
||||
description = "Connect to selected server only."; |
||||
}; |
||||
|
||||
bypassProxy = mkOption { |
||||
type = nullOr bool; |
||||
default = true; |
||||
description = "Bypass proxy."; |
||||
}; |
||||
|
||||
forceSSL = mkOption { |
||||
type = nullOr bool; |
||||
default = false; |
||||
description = "Use SSL for all servers."; |
||||
}; |
||||
|
||||
acceptInvalidSSLCertificates = mkOption { |
||||
type = nullOr bool; |
||||
default = false; |
||||
description = "Accept invalid SSL certificates."; |
||||
}; |
||||
|
||||
useGlobalUserInformation = mkOption { |
||||
type = nullOr bool; |
||||
default = false; |
||||
description = "Use global user information."; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
modChannelOption = with types; |
||||
submodule { |
||||
options = { |
||||
autojoin = mkOption { |
||||
type = listOf str; |
||||
default = [ ]; |
||||
example = [ "#home-manager" "#linux" "#nix" ]; |
||||
description = "Channels list to autojoin on connecting to server."; |
||||
}; |
||||
|
||||
charset = mkOption { |
||||
type = nullOr str; |
||||
default = null; |
||||
example = "UTF-8 (Unicode)"; |
||||
description = "Character set."; |
||||
}; |
||||
|
||||
commands = mkOption { |
||||
type = listOf str; |
||||
default = [ ]; |
||||
example = literalExample ''[ "ECHO Greetings fellow Nixer! ]''; |
||||
description = "Commands to be executed on connecting to server."; |
||||
}; |
||||
|
||||
loginMethod = mkOption { |
||||
type = nullOr (enum (attrNames loginMethodMap)); |
||||
default = null; |
||||
description = '' |
||||
The login method. The allowed options are: |
||||
<variablelist> |
||||
<varlistentry> |
||||
<term><literal>null</literal></term> |
||||
<listitem><para>Default</para></listitem> |
||||
</varlistentry> |
||||
<varlistentry> |
||||
<term><literal>"nickServMsg"</literal></term> |
||||
<listitem><para>NickServ (/MSG NickServ + password)</para></listitem> |
||||
</varlistentry> |
||||
<varlistentry> |
||||
<term><literal>"nickServ"</literal></term> |
||||
<listitem><para>NickServ (/NICKSERV + password)</para></listitem> |
||||
</varlistentry> |
||||
<varlistentry> |
||||
<term><literal>"challengeAuth"</literal></term> |
||||
<listitem><para>Challenge Auth (username + password)</para></listitem> |
||||
</varlistentry> |
||||
<varlistentry> |
||||
<term><literal>"sasl"</literal></term> |
||||
<listitem><para>SASL (username + password)</para></listitem> |
||||
</varlistentry> |
||||
<varlistentry> |
||||
<term><literal>"serverPassword"</literal></term> |
||||
<listitem><para>Server password (/PASS password)</para></listitem> |
||||
</varlistentry> |
||||
<varlistentry> |
||||
<term><literal>"saslExternal"</literal></term> |
||||
<listitem><para>SASL EXTERNAL (cert)</para></listitem> |
||||
</varlistentry> |
||||
<varlistentry> |
||||
<term><literal>"customCommands"</literal></term> |
||||
<listitem> |
||||
<para>Use "commands" field for auth. For example |
||||
<programlisting language="nix"> |
||||
commands = [ "/msg NickServ IDENTIFY my_password" ] |
||||
</programlisting> |
||||
</para> |
||||
</listitem> |
||||
</varlistentry> |
||||
</variablelist> |
||||
''; |
||||
}; |
||||
|
||||
nickname = mkOption { |
||||
type = nullOr str; |
||||
default = null; |
||||
description = "Primary nickname."; |
||||
}; |
||||
|
||||
nickname2 = mkOption { |
||||
type = nullOr str; |
||||
default = null; |
||||
description = "Secondary nickname."; |
||||
}; |
||||
|
||||
options = mkOption { |
||||
type = nullOr channelOptions; |
||||
default = null; |
||||
example = { |
||||
autoconnect = true; |
||||
useGlobalUserInformation = true; |
||||
}; |
||||
description = "Channel options."; |
||||
}; |
||||
|
||||
password = mkOption { |
||||
type = nullOr str; |
||||
default = null; |
||||
description = '' |
||||
Password to use. Note this password will be readable by all user's |
||||
in the Nix store. |
||||
''; |
||||
}; |
||||
|
||||
realName = mkOption { |
||||
type = nullOr str; |
||||
default = null; |
||||
description = '' |
||||
Real name. Is used to populate the real name field that appears when |
||||
someone uses the <literal>WHOIS</literal> command on your nick. |
||||
''; |
||||
}; |
||||
|
||||
userName = mkOption { |
||||
type = nullOr str; |
||||
default = null; |
||||
description = '' |
||||
User name. Part of your <literal>user@host</literal> hostmask that |
||||
appears to other on IRC. |
||||
''; |
||||
}; |
||||
|
||||
servers = mkOption { |
||||
type = listOf str; |
||||
default = [ ]; |
||||
example = [ "chat.freenode.net" "irc.freenode.net" ]; |
||||
description = "IRC Server Address List."; |
||||
}; |
||||
}; |
||||
}; |
||||
|
||||
transformField = k: v: if (v != null) then "${k}=${v}" else null; |
||||
|
||||
listChar = c: l: |
||||
if l != [ ] then concatMapStringsSep "\n" (transformField c) l else null; |
||||
|
||||
computeFieldsValue = channel: |
||||
let |
||||
ifTrue = p: n: if p then n else 0; |
||||
result = with channel.options; |
||||
foldl' (a: b: a + b) 0 [ |
||||
(ifTrue (!connectToSelectedServerOnly) 1) |
||||
(ifTrue useGlobalUserInformation 2) |
||||
(ifTrue forceSSL 4) |
||||
(ifTrue autoconnect 8) |
||||
(ifTrue (!bypassProxy) 16) |
||||
(ifTrue acceptInvalidSSLCertificates 32) |
||||
]; |
||||
in toString (if channel.options == null then 0 else result); |
||||
|
||||
loginMethodMap = { |
||||
nickServMsg = 1; |
||||
nickServ = 2; |
||||
challengeAuth = 4; |
||||
sasl = 6; |
||||
serverPassword = 7; |
||||
customCommands = 9; |
||||
saslExternal = 10; |
||||
}; |
||||
|
||||
loginMethod = channel: |
||||
transformField "L" (optionalString (channel.loginMethod != null) |
||||
(toString loginMethodMap.${channel.loginMethod})); |
||||
|
||||
# Note: Missing option `D=`. |
||||
transformChannel = channelName: |
||||
let channel = cfg.channels.${channelName}; |
||||
in concatStringsSep "\n" (filter (v: v != null) [ |
||||
"" # leave a space between one server and another |
||||
(transformField "N" channelName) |
||||
(loginMethod channel) |
||||
(transformField "E" channel.charset) |
||||
(transformField "F" (computeFieldsValue channel)) |
||||
(transformField "I" channel.nickname) |
||||
(transformField "i" channel.nickname2) |
||||
(transformField "R" channel.realName) |
||||
(transformField "U" channel.userName) |
||||
(transformField "P" channel.password) |
||||
(listChar "S" channel.servers) |
||||
(listChar "J" channel.autojoin) |
||||
(listChar "C" channel.commands) |
||||
]); |
||||
|
||||
in { |
||||
meta.maintainers = with maintainers; [ superherointj thiagokokada ]; |
||||
|
||||
options.programs.hexchat = with types; { |
||||
enable = mkEnableOption "HexChat, a graphical IRC client"; |
||||
|
||||
channels = mkOption { |
||||
type = attrsOf modChannelOption; |
||||
default = { }; |
||||
example = literalExample '' |
||||
{ |
||||
freenode = { |
||||
autojoin = [ |
||||
"#home-manager" |
||||
"#linux" |
||||
"#nixos" |
||||
]; |
||||
charset = "UTF-8 (Unicode)"; |
||||
commands = [ |
||||
"ECHO Buzz Lightyear sent you a message: 'To Infinity... and Beyond!'" |
||||
]; |
||||
loginMethod = sasl; |
||||
nickname = "my_nickname"; |
||||
nickname2 = "my_secondchoice"; |
||||
options = { |
||||
acceptInvalidSSLCertificates = false; |
||||
autoconnect = true; |
||||
bypassProxy = true; |
||||
connectToSelectedServerOnly = true; |
||||
useGlobalUserInformation = false; |
||||
forceSSL = false; |
||||
}; |
||||
password = "my_password"; |
||||
realName = "my_realname"; |
||||
servers = [ |
||||
"chat.freenode.net" |
||||
"irc.freenode.net" |
||||
]; |
||||
userName = "my_username"; |
||||
}; |
||||
}''; |
||||
description = '' |
||||
Configures <filename>~/.config/hexchat/servlist.conf</filename>. |
||||
''; |
||||
}; |
||||
|
||||
settings = mkOption { |
||||
default = null; |
||||
type = nullOr (attrsOf str); |
||||
example = literalExample '' |
||||
{ |
||||
irc_nick1 = "mynick"; |
||||
irc_username = "bob"; |
||||
irc_realname = "Bart Simpson"; |
||||
text_font = "Monospace 14"; |
||||
}; |
||||
''; |
||||
description = '' |
||||
Configuration for <filename>~/.config/hexchat/hexchat.conf</filename>, see |
||||
<link xlink:href="https://hexchat.readthedocs.io/en/latest/settings.html#list-of-settings"/> |
||||
for supported values. |
||||
''; |
||||
}; |
||||
|
||||
overwriteConfigFiles = mkOption { |
||||
type = nullOr bool; |
||||
default = false; |
||||
description = '' |
||||
Enables overwriting HexChat configuration files |
||||
(<filename>hexchat.conf</filename>, <filename>servlist.conf</filename>). |
||||
Any existing HexChat configuration will be lost. Certify to back-up any |
||||
previous configuration before enabling this. |
||||
</para><para> |
||||
Enabling this setting is recommended, because everytime HexChat |
||||
application is closed it overwrites Nix/Home Manager provided |
||||
configuration files, causing: |
||||
<orderedlist numeration="arabic"> |
||||
<listitem><para> |
||||
Nix/Home Manager provided configuration to be out of sync with |
||||
actual active HexChat configuration. |
||||
</para></listitem> |
||||
<listitem><para> |
||||
Blocking Nix/Home Manager updates until configuration files are |
||||
manually removed. |
||||
</para></listitem> |
||||
</orderedlist> |
||||
''; |
||||
}; |
||||
|
||||
theme = mkOption { |
||||
type = nullOr package; |
||||
default = null; |
||||
example = literalExample '' |
||||
stdenv.mkDerivation rec { |
||||
name = "hexchat-theme-MatriY"; |
||||
buildInputs = [ pkgs.unzip ]; |
||||
src = fetchurl { |
||||
url = "https://dl.hexchat.net/themes/MatriY.hct"; |
||||
sha256 = "sha256-ffkFJvySfl0Hwja3y7XCiNJceUrGvlEoEm97eYNMTZc="; |
||||
}; |
||||
unpackPhase = "unzip ''${src}"; |
||||
installPhase = "cp -r . $out"; |
||||
}; |
||||
''; |
||||
description = '' |
||||
Theme package for HexChat. Expects a derivation containing decompressed |
||||
theme files. <literal>.hct</literal> file format requires unzip |
||||
decompression, as seen in example. |
||||
''; |
||||
}; |
||||
}; |
||||
|
||||
config = mkIf cfg.enable { |
||||
assertions = [ |
||||
(hm.assertions.assertPlatform "programs.hexchat" pkgs platforms.linux) |
||||
]; |
||||
|
||||
home.packages = [ pkgs.hexchat ]; |
||||
|
||||
xdg.configFile."hexchat" = mkIf (cfg.theme != null) { |
||||
source = cfg.theme; |
||||
recursive = true; |
||||
}; |
||||
|
||||
xdg.configFile."hexchat/hexchat.conf" = mkIf (cfg.settings != null) { |
||||
force = cfg.overwriteConfigFiles; |
||||
text = concatMapStringsSep "\n" (x: x + " = " + cfg.settings.${x}) |
||||
(attrNames cfg.settings); |
||||
}; |
||||
|
||||
xdg.configFile."hexchat/servlist.conf" = mkIf (cfg.channels != { }) { |
||||
force = cfg.overwriteConfigFiles; |
||||
# Final line breaks is required to avoid cropping last field value. |
||||
text = concatMapStringsSep "\n" transformChannel (attrNames cfg.channels) |
||||
+ "\n\n"; |
||||
}; |
||||
}; |
||||
} |
@ -0,0 +1,10 @@ |
||||
dcc_dir = /home/user/Downloads |
||||
gui_quit_dialog = 0 |
||||
gui_slist_skip = 1 |
||||
irc_nick1 = user |
||||
irc_nick2 = user_ |
||||
irc_nick3 = user__ |
||||
irc_real_name = real user |
||||
irc_user_name = user |
||||
text_font = Monospace 14 |
||||
text_font_main = Monospace 14 |
@ -0,0 +1,24 @@ |
||||
|
||||
N=efnet |
||||
L= |
||||
F=4 |
||||
S=irc.choopa.net |
||||
S=irc.colosolutions.net |
||||
S=irc.mzima.net |
||||
S=irc.prison.net |
||||
J=#computers |
||||
|
||||
N=freenode |
||||
L=6 |
||||
E=UTF-8 (Unicode) |
||||
F=12 |
||||
I=user |
||||
i=user_ |
||||
R=real_user |
||||
U=user |
||||
P=password |
||||
S=chat.freenode.net |
||||
S=irc.freenode.net |
||||
J=#home-manager |
||||
J=#nixos |
||||
|
@ -0,0 +1,61 @@ |
||||
{ config, lib, pkgs, ... }: |
||||
|
||||
{ |
||||
config = { |
||||
programs.hexchat = { |
||||
enable = true; |
||||
overwriteConfigFiles = true; |
||||
channels = { |
||||
freenode = { |
||||
charset = "UTF-8 (Unicode)"; |
||||
userName = "user"; |
||||
password = "password"; |
||||
loginMethod = "sasl"; |
||||
nickname = "user"; |
||||
nickname2 = "user_"; |
||||
realName = "real_user"; |
||||
options = { |
||||
autoconnect = true; |
||||
forceSSL = true; |
||||
}; |
||||
servers = [ "chat.freenode.net" "irc.freenode.net" ]; |
||||
autojoin = [ "#home-manager" "#nixos" ]; |
||||
}; |
||||
efnet = { |
||||
options = { forceSSL = true; }; |
||||
servers = [ |
||||
"irc.choopa.net" |
||||
"irc.colosolutions.net" |
||||
"irc.mzima.net" |
||||
"irc.prison.net" |
||||
]; |
||||
autojoin = [ "#computers" ]; |
||||
}; |
||||
}; |
||||
settings = { |
||||
dcc_dir = "/home/user/Downloads"; |
||||
irc_nick1 = "user"; |
||||
irc_nick2 = "user_"; |
||||
irc_nick3 = "user__"; |
||||
irc_user_name = "user"; |
||||
irc_real_name = "real user"; |
||||
text_font = "Monospace 14"; |
||||
text_font_main = "Monospace 14"; |
||||
gui_slist_skip = "1"; # Skip network list on start-up |
||||
gui_quit_dialog = "0"; |
||||
}; |
||||
}; |
||||
|
||||
test.stubs.hexchat = { }; |
||||
|
||||
nmt.script = '' |
||||
assertFileContent \ |
||||
home-files/.config/hexchat/hexchat.conf \ |
||||
${./basic-configuration-expected-main-config} |
||||
assertFileContent \ |
||||
home-files/.config/hexchat/servlist.conf \ |
||||
${./basic-configuration-expected-serverlist-config} |
||||
''; |
||||
}; |
||||
|
||||
} |
@ -0,0 +1 @@ |
||||
{ hexchat-basic-configuration = ./basic-configuration.nix; } |
Loading…
Reference in new issue