https://wiki.znc.in/api.php?action=feedcontributions&user=DarthGandalf&feedformat=atomZNC - User contributions [en]2024-03-28T19:23:02ZUser contributionsMediaWiki 1.42.0-alphahttps://wiki.znc.in/index.php?title=Template:ZNC-Version-Alpha&diff=3127Template:ZNC-Version-Alpha2024-02-22T00:40:36Z<p>DarthGandalf: Blanked the page</p>
<hr />
<div></div>DarthGandalfhttps://wiki.znc.in/index.php?title=Template:ZNC-Version&diff=3126Template:ZNC-Version2024-02-22T00:40:32Z<p>DarthGandalf: </p>
<hr />
<div>1.9.0</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modperl&diff=3125Modperl2024-02-12T01:01:14Z<p>DarthGandalf: /* IRCv3 server-dependent capabilities */</p>
<hr />
<div>{{DISPLAYTITLE:modperl}}<br />
{{Core Module}}<br />
<br />
Modperl allows you to use modules written on perl. <br />
<br />
This page describes module since ZNC 0.095. If you still need help on old modperl, look [[Modperl/old|here]].<br />
<br />
__TOC__<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-perl or cmake with -DWANT_PERL=ON. <br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed. If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
== Usage ==<br />
Loading and unloading of perl modules is similar to C++ modules. For example, you can use <code>/znc loadmod</code> or [[webadmin]]. <br />
<br />
If you unload modperl, all perl modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Writing new perl modules ==<br />
=== Basics ===<br />
<br />
Every perl module is file named like <code>modulename.pm</code> and is located in usual modules directories.<br />
The file must contain package with exactly the same name as the module itself.<br />
The module should be derived from <code>ZNC::Module</code>. <br />
<pre><br />
# perlexample.pm<br />
<br />
package perlexample;<br />
use base 'ZNC::Module';<br />
<br />
sub description {<br />
"Example perl module for ZNC"<br />
}<br />
<br />
sub OnChanMsg {<br />
my $self = shift;<br />
my ($nick, $chan, $msg) = @_;<br />
$self->PutModule("Hey, ".$nick->GetNick." said [$msg] on ".$chan->GetName);<br />
return $ZNC::CONTINUE;<br />
}<br />
<br />
1;<br />
</pre><br />
If you want to define several perl packages inside your module, you should name them as subpackages of your module package.<br />
See [[#Sockets|Sockets]] section for example. <br />
<br />
Description of the module is the return value from a <code>sub description</code>.<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in perl.<br />
The exception is callbacks which get vector<...> as last argument:<br />
<pre><br />
virtual void OnQuit(const CNick& Nick, const CString& sMessage, ''const vector<CChan*>& vChans'');<br />
</pre><br />
<pre><br />
sub OnQuit {<br />
my ($self, $nick, $message, ''@chans'') = @_;<br />
for (@chans) {<br />
$self->PutIRC("PRIVMSG ".$_->GetName." :Poor ".$nick->GetNick." :(");<br />
}<br />
}<br />
</pre><br />
<code>sub OnShutdown</code> is used as destructor (instead of perl's <code>DESTROY</code>).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded. <br />
<br />
If a callback returns undef, a reasonable default is substituted.<br />
Remember that if execution comes to end of sub, last evaluated value is returned!<br />
If a callback dies/croaks, the default value is assumed too, the behavior of what happens to arguments is undefined.<br />
When a module callback should return <code>CModule::EModRet</code>, you can use values as <code>$ZNC::CModule::CONTINUE</code> or just <code>$ZNC::CONTINUE</code>. <br />
<br />
Don't begin names of your member data fields with underscore (_) - some of them are used by modperl internally. <br />
<pre><br />
sub OnShutdown {<br />
my $self = shift;<br />
$self->{foo} = "foo"; # OK<br />
$self->{_bar} = "bar"; # Fail, probably will work but can randomly stop working.<br />
}<br />
</pre><br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for perl modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user perl modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
package perlusermod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::UserModule }<br />
<br />
For global modules use this:<br />
package perlglobalmod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::GlobalModule }<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
package perlusernetworkmod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::UserModule, $ZNC::CModInfo::NetworkModule }<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod perlusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the functions like shown below:<br />
<br />
sub module_types { ... (see above section) }<br />
sub description { "This module does this and that" }<br />
sub wiki_page { "my_module" }<br />
sub has_args { 1 } # the default is 0<br />
sub args_help_text { "The arguments are foo and bar" }<br />
<br />
=== Strings ===<br />
All ZNC classes are accessible from perl with <code>ZNC::</code> prefix.<br />
The exception is <code>CString</code>. All uses of <code>CString</code> by value are transparently translated to/from perl string scalars. <br />
<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# perl<br />
my $str = "bar";<br />
ZNC::Foo($str); # OK<br />
my $num = 42;<br />
ZNC::Foo($num); # OK (only for ZNC >= 0.097)<br />
ZNC::Foo("$num"); # OK<br />
ZNC::Foo($num . ""); # OK<br />
ZNC::Foo(ZNC::String->new($num)); # OK, see below about ZNC::String<br />
<br />
If you need to ''call'' a function which gets <code>CString</code> by reference, and returns a value in it, there's a class named <code>ZNC::String</code>: <br />
<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# perl<br />
my $s = ZNC::String->new;<br />
ZNC::Foo($s);<br />
print $s->GetPerlStr; # prints 'bar' to stdout<br />
print $s; # The same, only for ZNC >= 1.7.0.<br />
<br />
As you see, to get normal string from <code>ZNC::String</code> there's a method <code>GetPerlStr</code>. Since ZNC 1.7.0 it's called automatically when string is needed.<br />
You can construct non-empty <code>ZNC::String</code> using an argument to <code>new</code>.<br />
This constructor can get string scalars, integer scalars, float scalars. <br />
<br />
When you implement a module hook which accepts <code>CString&</code>, no <code>ZNC::String</code> magic is needed, it just works: <br />
<pre><br />
sub OnChanMsg {<br />
my $self = shift;<br />
# @_ == (nick, channel, message)<br />
if ($_[0]->GetNick eq "Fish" || $_[2] eq "kwaa") {<br />
$_[2] = "moo!"<br />
}<br />
# the code above can be rewritten as follows:<br />
my ($nick, $channel, $message) = map {\$_} @_;<br />
if ($$nick->GetNick eq "Fish" || $$message eq "kwaa") {<br />
$$message = "moo!";<br />
}<br />
# alternatively, use \shift<br />
}<br />
</pre><br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
my $num_msg = $msg->As('CNumericMessage');<br />
</pre><br />
<br />
=== Module's NV ===<br />
There're some issues with using std iterators from perl, so class <code>CModule</code> got new methods: <code>GetNVKeys</code> which returns list of names of all NV values of the module, and <code>ExistsNV</code> which checks if specified variable exists. <br />
<pre><br />
sub OnModCommand {<br />
my $self = shift;<br />
my @nvkeys = $self->GetNVKeys;<br />
if ($self->ExistsNV("foo")) {<br />
$self->SetNV("bar", $self->GetNV("foo"));<br />
$self->DelNV("foo");<br />
}<br />
....<br />
}<br />
</pre><br />
Also there's another interface for accessing NVs - perl hash. (But for big number of values it's slow) <br />
<pre><br />
sub OnModCommand {<br />
my $self = shift;<br />
my $nv = $self->NV;<br />
while (my ($key, $value) = each %$nv) {<br />
...<br />
}<br />
my @nvkeys = keys %$nv;<br />
$nv->{foo} = "bar";<br />
$self->PutModule($nv->{foo});<br />
delete $nv->{foo};<br />
}<br />
</pre><br />
Of course, you can use $self->{foo} for storing temporary values, but NV data is stored on disk.<br />
<br />
=== IRCv3 server-dependent capabilities ===<br />
<br />
Available since ZNC 1.9. (Server-independent caps can be implemented before that, but with the same API as in C++ modules) <br />
<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>$self->AddServerDependentCapability()</code> accepts two code references:<br />
<br />
sub OnLoad {<br />
my $self = shift;<br />
$self->AddServerDependentCapability('testcap', sub {<br />
my ($ircnetwork, $state) = @_;<br />
$self->PutModule('Server changed support: ' . ($state ? 'true' : 'false'));<br />
}, sub {<br />
my ($client, $state) = @_;<br />
$self->PutModule('Client changed support: ' . ($state ? 'true' : 'false'));<br />
});<br />
return 1;<br />
}<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module. <br />
sub GetWebMenuTitle {<br />
"Perl test module"<br />
}<br />
==== CTemplate ====<br />
<br />
Instead of operator[] use set:<br />
<pre><br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
</pre><br />
<pre><br />
# perl equivalent<br />
my $tmpl = ...;<br />
$tmpl->set("name", "value");<br />
my $row = $tmpl->AddRow("SomeTable");<br />
$row->set("foo", "bar");<br />
</pre><br />
==== Subpages ====<br />
If you want to have subpages for the module, use helper function <code>ZNC::CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional named arguments: <br />
* title - text for displaying subpage name. By default it's the same as name. <br />
* params - reference to hash of parameters which will be used in URL linking to the subpage. <br />
* admin - set to true value if subpage should be accessible only by admins. <br />
<br />
There're 2 ways: using <code>AddSubPage</code>/<code>ClearSubPages</code> and overriding <code>GetSubPages</code>. <br />
<pre><br />
sub OnLoad {<br />
my $self = shift;<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page1'));<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page2', title=>'Page N2'));<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page3', params=>{var1=>'value1', var2=>'value2'}, admin=>1);<br />
1<br />
}<br />
</pre><br />
The second way - to override <code>GetSubPages</code>. Perhaps(?) it may be better if list of subpages changes often in runtime. <br />
<br />
But don't return pointer to local variable! Perl destroys objects when reference count goes to zero. In these 2 examples additional reference to returned object is stored in <code>$self->{webpages}</code>. <br />
<pre><br />
sub OnLoad {<br />
my $self = shift;<br />
$self->{webpages} = ZNC::VWebSubPages->new;<br />
1<br />
}<br />
sub OnModCommand {<br />
my $self = shift;<br />
my $cmd = shift;<br />
$self->{webpages}->push(ZNC::CreateWebSubPage($cmd));<br />
}<br />
sub GetSubPages {<br />
my $self = shift;<br />
return $self->{webpages}<br />
}<br />
</pre><br />
<pre><br />
sub GetSubPages {<br />
my $self = shift;<br />
my $result = ZNC::VWebSubPages->new;<br />
$result->push(ZNC::CreateWebSubPage('foo'));<br />
$self->{webpages} = $result;<br />
return $result;<br />
}<br />
</pre><br />
<br />
=== Timers ===<br />
There're 2 APIs: first uses references to subs, second uses OOP packages. <br />
==== Ref API ====<br />
<br />
Use helper function <code>CreateTimer</code>.<br />
It gets following named arguments: <br />
* task ''(required)'' - Reference to a sub which will be called. The sub gets reference to your module as first argument, and ''context'' as named argument. <br />
* interval - Interval between calls, in seconds. Default is 10. <br />
* cycles - Number of times to run the sub. 0 means infinite. Default is 1. <br />
* description - Text description of the timer. Default doesn't matter. <br />
* label ''(overrideable since ZNC 1.9)'' - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default value is <code>perl-timer</code>.<br />
* context - Arbitrary value, which ''task'' will get as named argument context. <br />
<pre><br />
sub foo {<br />
my $self = shift;<br />
my %arg = @_;<br />
$self->PutStatus("foo ".$arg{context});<br />
}<br />
sub OnModCommand {<br />
my $self = shift;<br />
$self->CreateTimer(task=>\&foo, interval=>5, context=>'bar',<br />
description=>"Timer which puts 'foo bar' to status in 5 secs after user wrote something to the module");<br />
$self->CreateTimer(task=>sub {}, cycles=>0, interval=>1, description=>"Timer which every 1 second does nothing");<br />
}<br />
</pre><br />
==== OOP API ====<br />
''(available since ZNC 0.097) ''<br />
<br />
Use helper function <code>CreateTimer</code>. It gets following named arguments: <br />
* task ''(required)'' - name of your Timer class. It should be derived from <code>ZNC::Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>. <br />
* interval - Interval between calls, in seconds. Default is 10. <br />
* cycles - Number of times to run the sub. 0 means infinite. Default is 1. <br />
* description - Text description of the timer. Default doesn't matter. <br />
* label ''(overrideable since ZNC 1.9)'' - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default value is <code>perl-timer</code>.<br />
<pre><br />
# timerooptest.pm<br />
use strict;<br />
use warnings;<br />
<br />
package timerooptest::timer;<br />
use base 'ZNC::Timer';<br />
sub RunJob {<br />
my $self = shift;<br />
$self->GetModule->PutStatus('foo '.$self->{msg});<br />
}<br />
<br />
package timerooptest;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my $self = shift;<br />
my $timer = $self->CreateTimer(task=>'timerooptest::timer', interval=>4, cycles=>1,<br />
description=>'Says "foo bar" after 4 seconds');<br />
$timer->{msg} = 'bar';<br />
}<br />
</pre><br />
You can use methods of C++ class <code>CTimer</code> (like Stop) for your timer.<br />
<br />
=== Sockets ===<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special functions, which return true scalar if the feature is supported. <br />
<pre><br />
if (ZNC::HaveIPv6) {<br />
...<br />
}<br />
if (ZNC::HaveSSL) {<br />
...<br />
}<br />
if (ZNC::HaveCAres) {<br />
...<br />
}<br />
</pre><br />
All sockets are instances of special classes derived from <code>ZNC::Socket</code>.<br />
<code>ZNC::Socket</code> has all the same methods as <code>Csock</code>, except <code>Connect</code> and <code>Listen</code>.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to the associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of <code>Csock</code>, they are described later.<br />
<br />
To create socket, use module's method <code>CreateSocket</code>.<br />
First argument is the name of your socket class.<br />
The function creates socket and calls method <code>Init</code> of it with the rest of arguments.<br />
Reference to the new socket is returned. <br />
<br />
To connect socket, use method <code>Connect</code>.<br />
It gets 2 required arguments - hostname and port, and several optional named arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60. <br />
* ssl - Whether to use SSL for connection. <br />
* bindhost - Local interface to use for the connection. <br />
<br />
Returns true value if connection scheduled successfully.<br />
<pre><br />
# testmodule.pm<br />
<br />
package testmodule::connsock;<br />
use base 'ZNC::Socket';<br />
sub Init {<br />
my $self = shift;<br />
my $line = shift; # this and following arguments can be specified in CreateSocket<br />
$self->Connect('google.com', 80);<br />
$self->EnableReadLine;<br />
$self->Write("$line\r\n");<br />
}<br />
sub OnReadLine {<br />
my ($self, $line) = @_;<br />
$line =~ s/[\r\n]//g;<br />
$self->GetModule->PutStatus($line);<br />
}<br />
<br />
package testmodule;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my ($self, $cmd) = @_;<br />
my $sock = $self->CreateSocket('testmodule::connsock', "GET $cmd HTTP/1.0\r\n");<br />
}<br />
<br />
1;<br />
</pre><br />
<pre><br />
# testmodule2.pm<br />
<br />
package testmodule2::conn;<br />
use base 'ZNC::Socket';<br />
sub OnReadLine {<br />
my ($self, $line) = @_;<br />
$line =~ s/[\r\n]//g;<br />
$self->GetModule->PutStatus($line);<br />
}<br />
<br />
package testmodule2;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my ($self, $cmd) = @_;<br />
my $sock = $self->CreateSocket('testmodule2::connsock');<br />
$sock->Connect('google.com', 443, ssl=>1);<br />
$sock->EnableReadLine;<br />
$sock->Write("GET $cmd HTTP/1.0\r\n\r\n");<br />
}<br />
<br />
1;<br />
</pre><br />
<br />
To create listening socket, use method <code>Listen</code>.<br />
It gets following optional named arguments: <br />
* port - Port number to listen on. If not presented, random port is choosed. <br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces. <br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all. <br />
* ssl - Whether to use SSL for incoming connections. <br />
* maxconns - Maximum number of connections. Default is SOMAXCONN. <br />
* timeout - time in seconds, for timeout. <br />
<br />
Returns 0 on error and port number on success. <br />
<pre><br />
# testmodule3.pm<br />
<br />
package testmodule3::listensock;<br />
use base 'ZNC::Socket';<br />
sub OnAccepted {<br />
my ($self, $host, $port) = @_;<br />
$self->GetModule->CreateSocket('testmodule3::accepted', $host, $port);<br />
}<br />
<br />
package testmodule3::accepted;<br />
use base 'ZNC::Socket';<br />
sub Init {<br />
my ($self, $host, $port) = @_;<br />
$self->Write("Hello, $host:$port!\n");<br />
}<br />
sub OnReadData {<br />
my $self = shift;<br />
my ($data, $len) = @_;<br />
$self->Write($data, $len); # echo back everything<br />
}<br />
<br />
package testmodule3;<br />
use base 'ZNC::Module';<br />
sub OnLoad {<br />
my $self = shift;<br />
my $sock = $self->CreateSocket('testmodule3::listensock');<br />
my $port = $sock->Listen(ssl=>1, addrtype=>'ipv6');<br />
if ($port) {<br />
$_[1] = "Listening on all IPv6 interfaces on port $port using SSL";<br />
}<br />
1<br />
}<br />
<br />
1;<br />
</pre><br />
Sockets can override following callbacks: <br />
* <code>Init</code> - is called from <code>CreateSocket</code>, first argument is reference to socket, the rest is from arguments to <code>CreateSocket</code>. <br />
* <code>OnConnected</code><br />
* <code>OnDisconnected</code><br />
* <code>OnTimeout</code><br />
* <code>OnConnectionRefused</code><br />
* <code>OnReadData</code> - gets 2 arguments (of course, excluding reference to self): data and number of bytes. <br />
* <code>OnReadLine</code> - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket. <br />
* <code>OnAccepted</code> - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return undef if you don't need the connection, or reference to new socket, which will be used for this connection. <br />
* <code>OnShutdown</code> - ''(since 0.097)'' destructor of the socket. <br />
<br />
If callback <code>On*</code> dies/croaks, the socket is closed, but if you want to close socket, use method <code>Close</code> instead. If <code>Init</code> croaks, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>ZNC::CZNC::GetTag</code> is good. <br />
ZNC::CZNC::GetTag() # Returns, for example, 'ZNC 0.097 - http://znc.sourceforge.net'<br />
<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
Since ZNC 0.097, for getting ZNC version from Perl modules, you can use following functions: <br />
ZNC::GetVersion() # For example, number 0.097<br />
ZNC::GetVersionMajor() # 0<br />
ZNC::GetVersionMinor() # 97<br />
ZNC::GetVersionExtra() # build-specific string<br />
<br />
== Perl module Examples ==<br />
Here is a listing of useful perl modules<br />
* [https://github.com/DarthGandalf/znclinker ZNC-Linker bot]<br />
* [https://github.com/draggy/znc-perl-bitlbee-facebook-rename Facebook Bitlbee Rename]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modpython&diff=3124Modpython2024-02-11T11:41:19Z<p>DarthGandalf: /* IRCv3 server-dependent capabilities */</p>
<hr />
<div>{{DISPLAYTITLE:modpython}}<br />
{{Core Module}}<br />
<br />
Modpython allows you to use modules written on python 3.<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-python, or cmake with -DWANT_PYTHON=ON.<br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed (Note: Must be => 3.0.0). If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
If for some reason you chose to compile python3 yourself, do it with --enable-shared option. If you use python from your distro (e.g. via apt-get, yum, etc), it is already compiled in the right way, no need to recompile anything.<br />
<br />
If python was compiled without this option, you may see errors like this: <code>/usr/local/lib/znc/modpython.so: undefined symbol: forkpty</code><br />
<br />
== Usage ==<br />
<br />
Loading and unloading of python3 modules is similar to C++ modules.<br />
For example, you can use <code>/znc loadmod</code> or [[webadmin]].<br />
<br />
If you unload modpython, all python modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Caveats ==<br />
* Python multithreading doesn't work properly. However you may try multiprocessing.<br />
* ZNC executes most of the operations (including Python modules) in single thread. It means you need to be careful not to block current thread, instead all your IRC connections may timeout. Webadmin will also stop working. Ideally you offload heavy operations to separate thread. Or actually to separate process, since multithreading doesn't work.<br />
<br />
== Writing new python3 modules ==<br />
=== Basics ===<br />
<br />
Every python module is file named like modulename.py (since ZNC 1.9 you can also use the package and name it modulename/__init__.py) and is located in usual modules directories (see [[Modules#Managing_Modules|here]] for details).<br />
The file '''must''' contain class with exactly the same name as the module itself.<br />
The class should be derived from <code>znc.Module</code>.<br />
<br />
# pythonexample.py<br />
<br />
import znc<br />
<br />
class pythonexample(znc.Module):<br />
description = "Example python3 module for ZNC"<br />
<br />
def OnChanMsg(self, nick, channel, message):<br />
self.PutModule("Hey, {0} said {1} on {2}".format(nick.GetNick(), message.s, channel.GetName()))<br />
return znc.CONTINUE<br />
<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in python.<br />
<br />
<code>def OnShutdown</code> is used as destructor (instead of python's __del__).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded.<br />
<br />
If a callback returns None or doesn't return anything instead of returning something (except for the <code>void</code> return type, of course), the behavior can be bizzare. Do not do this, even though sometimes it appears to work fine. In some future version this may be changed to check return types more strictly. The same goes for exceptions raised from the callback.<br />
<br />
When a module callback should return CModule::EModRet, you can use values such as <code>znc.CModule.CONTINUE</code> or just <code>znc.CONTINUE</code>.<br />
<br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for python modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user python modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
class pyusermod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule]<br />
<br />
For global modules use this:<br />
class pyglobalmod(znc.Module):<br />
module_types = [znc.CModInfo.GlobalModule]<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
class pyusernetworkmod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule, znc.CModInfo.NetworkModule]<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod pyusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the attributes like shown below:<br />
<br />
module_types = ... (see above section)<br />
description = "This module does this and that"<br />
wiki_page = "my_module"<br />
has_args = True (the default is False)<br />
args_help_text = "The arguments are foo and bar"<br />
<br />
=== Strings ===<br />
<br />
All ZNC classes are accessible from python with <code>znc.</code> prefix. The exception is CString.<br />
All uses of CString ''by value'' is transparently translated to/from python string objects.<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# python<br />
znc.Foo("bar")<br />
The same for case where you get CString by value:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(''const CString& sArgsi'', CString& sMessage);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if args == "bar":<br />
return True<br />
return False<br />
If you need to use CString ''by reference'', use class <code>znc.String</code> and its attribute <code>s</code>:<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# python<br />
x = znc.String()<br />
znc.Foo(x);<br />
print(x.s); # prints 'bar' to stdout<br />
The same if you get CString& as argument:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgsi, ''CString& sMessage'');<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
message.s = 'bar'<br />
return True<br />
<br />
'''Note''': don't try to use the string which you got in the overloaded method for calls to other methods<br />
<br />
# C++<br />
class CModule {<br />
virtual void OnFoo(CString& sMsg);<br />
void Bar(CString& sMsg); // appends "Bar" to sMsg<br />
}<br />
<br />
# python, wrong way<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
self.Bar(msg) # ZNC crashes here<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
s = znc.String()<br />
s.s = msg.s # so that old value is preserved<br />
self.Bar(s)<br />
msg.s = s.s # put result back to ''msg''<br />
<br />
So, you want to override a hook <code>void OnFoo(const CString& sBar)</code> and you actually don't want to write to <code>sBar</code>. So you probably will want to use the argument as python string. But, let's assume that in next ZNC version <code>OnFoo</code>'s signature will be changed to <code>void OnFoo(CString& sBar)</code>. This will break your module! To be on safe side, convert the argument to string with usual <code>str()</code> function. ('''Note:''' support for <code>str()</code> was added in ZNC 0.099) <br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgs, CString& sMessage);<br />
virtual EModRet OnRaw(CString& sLine);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if str(args).startswith('bar'):<br />
...<br />
def OnRaw(self, line):<br />
if str(line).startswith('bar'):<br />
...<br />
<br />
=== Booleans ===<br />
Moost booleans just work. If a callback gets <code>bool&</code> as a parameter, use this:<br />
<br />
// C++<br />
virtual EModRet OnModuleLoading(const CString& sModName, const CString& sArgs,<br />
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg);<br />
<br />
# python<br />
def OnModuleLoading(self, name, args, typ, success, retmsg):<br />
success.b = False # similar to string with its .s<br />
return znc.HALT<br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
num_msg = msg.As(znc.CNumericMessage)<br />
</pre><br />
<br />
=== Module's NV ===<br />
<br />
<code>module.nv</code> is a dict-like object, which can be used as normal dict, but stores it's data on disk. Both keys and values should be strings.<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
self.nv['bar'] = 'baz'<br />
if 'abcde' in self.nv:<br />
try:<br />
message.s = self.nv['qwerty']<br />
except KeyError:<br />
message.s = self.nv['abcde']<br />
for k, v = self.nv.items():<br />
...<br />
<br />
=== Objects ===<br />
<br />
SWIG distinguish between instances from ZNC and instances created in Python. All instances that are created during python time are garbage collected as soon they leave scope (e.g. at the end of the function or module). To move an instance to the ZNC scope, so it can be used after the lifetime of the function/module, set the special object property .thisown to 0.<br />
<br />
For example this is required if you add new user:<br />
<br />
new_user = znc.CUser(username)<br />
str_err = znc.String()<br />
if znc.CZNC.Get().AddUser(new_user, str_err):<br />
new_user.thisown = 0 # new_user won't be garbage collected at the end of the function anymore<br />
<br />
Similiar if you want to free an instance (like removing a listener), you should make sure that the memory gets garbage collected<br />
<br />
listener = ...<br />
if znc.CZNC.Get().DelListener(listener):<br />
listener.thisown = 1<br />
<br />
=== IRCv3 server-dependent capabilities ===<br />
<br />
Available since ZNC 1.9. (Server-independent caps can be implemented before that, but with the same API as in C++ modules)<br />
<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>self.AddServerDependentCapability()</code> accepts two callable objects:<br />
<br />
def OnLoad(self, args, ret):<br />
def server_change(ircnetwork, state):<br />
self.PutModule('Server changed support: ' + ('true' if state else 'false'))<br />
def client_change(client, state):<br />
self.PutModule('Client changed support: ' + ('true' if state else 'false'))<br />
self.AddServerDependentCapability('testcap', server_change, client_change)<br />
return True<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module.<br />
class test(znc.Module):<br />
def GetWebMenuTitle(self):<br />
return "Python test module"<br />
<br />
==== CTemplate ====<br />
<br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
<br />
# python equivalent (0.206 and below)<br />
tmpl = ...;<br />
tmpl.set("name", "value")<br />
row = tmpl.AddRow("SomeTable")<br />
row.set("foo", "bar")<br />
<br />
# python equivalent (since 0.207)<br />
tmpl = ...;<br />
tmpl["name"] = "value"<br />
row = tmpl.AddRow("SomeTable")<br />
row["foo"] = "bar"<br />
<br />
==== Subpages ====<br />
If you want to have subpages for the module, besides the main page, use helper function <code>znc.CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional arguments:<br />
* title - text for displaying subpage name. By default it's the same as name.<br />
* params - dict of parameters which will be used in URL linking to the subpage.<br />
* admin - set to True if subpage should be accessible only by admins.<br />
<br />
def OnLoad(self, args, message):<br />
self.AddSubPage(znc.CreateWebSubPage('page1'));<br />
self.AddSubPage(znc.CreateWebSubPage('page2', title='Page N2'))<br />
self.AddSubPage(znc.CreateWebSubPage('page3', params=dict(var1='value1', var2='value2'), admin=True))<br />
return True<br />
<br />
=== Timers ===<br />
Use helper function <code>CreateTimer</code>. It gets following arguments:<br />
* timer ''(required)'' - reference to your Timer class. It should be derived from <code>znc.Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>.<br />
* interval - Interval between calls, in seconds. Default is 10.<br />
* cycles - Number of times to run the <code>RunJob</code> function. 0 means infinite. Default is 1.<br />
* description - Text description of the timer. Default doesn't matter.<br />
* label - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default is <code>pytimer</code>.<br />
# timertest.py<br />
import znc<br />
<br />
class testtimer(znc.Timer):<br />
def RunJob(self):<br />
self.GetModule().PutStatus('foo {0}'.format(self.msg))<br />
<br />
class timertest(znc.Module):<br />
def OnModCommand(self, cmd):<br />
timer = self.CreateTimer(testtimer, interval=4, cycles=1, description='Says "foo bar" after 4 seconds', label='moo')<br />
timer.msg = 'bar'<br />
<br />
You can use methods of C++ class <code>CTimer</code> (like <code>Stop</code>) for your timer.<br />
<br />
=== Sockets ===<br />
<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special variables, which are True if the feature is supported.<br />
if znc.HaveIPv6:<br />
...<br />
if znc.HaveSSL:<br />
...<br />
if znc.HaveCAres:<br />
...<br />
All sockets are instances of special classes derived from <code>znc.Socket</code>.<br />
znc.Socket has all the same methods as Csock, except Connect, Listen and Write.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of Csock, they are described later.<br />
<br />
To create socket, use module's method CreateSocket. First argument is reference to your socket class. The function creates socket and calls method <code>Init</code> of it with the rest of arguments. Reference to the new socket is returned.<br />
<br />
To connect socket, use method <code>Connect</code>. It gets 2 required arguments - hostname and port, and several optional arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60.<br />
* ssl - Whether to use SSL for connection.<br />
* bindhost - Local interface to use for the connection.<br />
Returns true value if connection scheduled successfully.<br />
<br />
# networkconn.py<br />
import znc<br />
class connsock(znc.Socket):<br />
def Init(self, line): # line and other arguments, including named arguments can be specified in CreateSocket<br />
self.Connect('google.com', 80)<br />
self.EnableReadLine()<br />
self.Write("{0}\r\n".format(line))<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line) # this puts also \n and \r to status, which is not very good, but this is just an example, so...<br />
<br />
class networkconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(connsock, "GET {0} HTTP/1.0\r\n".format(cmd))<br />
<br />
# socketconn.py<br />
import znc<br />
class conn(znc.Socket):<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line)<br />
<br />
class socketconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(conn)<br />
sock.Connect('google.com', 443, ssl=True)<br />
sock.EnableReadLine()<br />
sock.Write("GET {0} HTTP/1.0\r\n\r\n".format(cmd))<br />
<br />
To create listening socket, use method <code>Listen</code>. It gets following optional named arguments:<br />
* port - Port number to listen on. If not presented, random port is choosed.<br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces.<br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all.<br />
* ssl - Whether to use SSL for incoming connections.<br />
* maxconns - Maximum number of connections. Default is SOMAXCONN.<br />
* timeout - time in seconds, for timeout.<br />
Returns 0 on error and port number on success.<br />
# listmodule.py<br />
import znc<br />
<br />
class accepted(znc.Socket):<br />
def Init(self, host, port):<br />
self.Write("Hello, {0}:{1}!\n".format(host, port))<br />
def OnReadData(self, data):<br />
self.WriteBytes(data) # echo back everything<br />
<br />
class listensock(znc.Socket):<br />
def OnAccepted(self, host, port):<br />
return self.GetModule().CreateSocket(accepted, host, port)<br />
<br />
class listmodule(znc.Module):<br />
def OnLoad(self, args, message):<br />
sock = self.CreateSocket(listensock)<br />
port = sock.Listen(ssl=True, addrtype='ipv6');<br />
if port > 0:<br />
message.s = "Listening on all IPv6 interfaces on port {0} using SSL".format(port)<br />
return True<br />
<br />
Use <code>Write</code> to write strings, and <code>WriteBytes</code> to write binary data.<br />
<br />
Sockets can override following callbacks:<br />
* Init - is called from CreateSocket, first argument is reference to socket, the rest is from arguments to CreateSocket.<br />
* OnConnected<br />
* OnDisconnected<br />
* OnTimeout<br />
* OnConnectionRefused<br />
* OnReadData - gets bytes as second argument<br />
* OnReadLine - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket.<br />
* OnAccepted - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return None if you don't need the connection, or reference to new socket, which will be used for this connection.<br />
* OnShutdown - destructor of the socket.<br />
<br />
If callback On* raises an exception, the socket is closed, but if you want to close socket, use method <code>Close</code> instead.<br />
If Init raises an exception, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>znc.CZNC.GetTag()</code> is good.<br />
znc.CZNC.GetTag() # Returns, for example, 'ZNC 0.097 - http:/<nowiki></nowiki>/znc.sourceforge.net'<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
For getting ZNC version, you can use read following variables:<br />
znc.Version # For example, number 0.097<br />
znc.VersionMajor # 0<br />
znc.VersionMinor # 97<br />
znc.VersionExtra # build-specific string<br />
<br />
<br />
[[Category:Modules]]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modperl&diff=3123Modperl2024-02-11T10:56:42Z<p>DarthGandalf: /* IRCv3 server-dependent capabilities */</p>
<hr />
<div>{{DISPLAYTITLE:modperl}}<br />
{{Core Module}}<br />
<br />
Modperl allows you to use modules written on perl. <br />
<br />
This page describes module since ZNC 0.095. If you still need help on old modperl, look [[Modperl/old|here]].<br />
<br />
__TOC__<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-perl or cmake with -DWANT_PERL=ON. <br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed. If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
== Usage ==<br />
Loading and unloading of perl modules is similar to C++ modules. For example, you can use <code>/znc loadmod</code> or [[webadmin]]. <br />
<br />
If you unload modperl, all perl modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Writing new perl modules ==<br />
=== Basics ===<br />
<br />
Every perl module is file named like <code>modulename.pm</code> and is located in usual modules directories.<br />
The file must contain package with exactly the same name as the module itself.<br />
The module should be derived from <code>ZNC::Module</code>. <br />
<pre><br />
# perlexample.pm<br />
<br />
package perlexample;<br />
use base 'ZNC::Module';<br />
<br />
sub description {<br />
"Example perl module for ZNC"<br />
}<br />
<br />
sub OnChanMsg {<br />
my $self = shift;<br />
my ($nick, $chan, $msg) = @_;<br />
$self->PutModule("Hey, ".$nick->GetNick." said [$msg] on ".$chan->GetName);<br />
return $ZNC::CONTINUE;<br />
}<br />
<br />
1;<br />
</pre><br />
If you want to define several perl packages inside your module, you should name them as subpackages of your module package.<br />
See [[#Sockets|Sockets]] section for example. <br />
<br />
Description of the module is the return value from a <code>sub description</code>.<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in perl.<br />
The exception is callbacks which get vector<...> as last argument:<br />
<pre><br />
virtual void OnQuit(const CNick& Nick, const CString& sMessage, ''const vector<CChan*>& vChans'');<br />
</pre><br />
<pre><br />
sub OnQuit {<br />
my ($self, $nick, $message, ''@chans'') = @_;<br />
for (@chans) {<br />
$self->PutIRC("PRIVMSG ".$_->GetName." :Poor ".$nick->GetNick." :(");<br />
}<br />
}<br />
</pre><br />
<code>sub OnShutdown</code> is used as destructor (instead of perl's <code>DESTROY</code>).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded. <br />
<br />
If a callback returns undef, a reasonable default is substituted.<br />
Remember that if execution comes to end of sub, last evaluated value is returned!<br />
If a callback dies/croaks, the default value is assumed too, the behavior of what happens to arguments is undefined.<br />
When a module callback should return <code>CModule::EModRet</code>, you can use values as <code>$ZNC::CModule::CONTINUE</code> or just <code>$ZNC::CONTINUE</code>. <br />
<br />
Don't begin names of your member data fields with underscore (_) - some of them are used by modperl internally. <br />
<pre><br />
sub OnShutdown {<br />
my $self = shift;<br />
$self->{foo} = "foo"; # OK<br />
$self->{_bar} = "bar"; # Fail, probably will work but can randomly stop working.<br />
}<br />
</pre><br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for perl modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user perl modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
package perlusermod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::UserModule }<br />
<br />
For global modules use this:<br />
package perlglobalmod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::GlobalModule }<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
package perlusernetworkmod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::UserModule, $ZNC::CModInfo::NetworkModule }<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod perlusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the functions like shown below:<br />
<br />
sub module_types { ... (see above section) }<br />
sub description { "This module does this and that" }<br />
sub wiki_page { "my_module" }<br />
sub has_args { 1 } # the default is 0<br />
sub args_help_text { "The arguments are foo and bar" }<br />
<br />
=== Strings ===<br />
All ZNC classes are accessible from perl with <code>ZNC::</code> prefix.<br />
The exception is <code>CString</code>. All uses of <code>CString</code> by value are transparently translated to/from perl string scalars. <br />
<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# perl<br />
my $str = "bar";<br />
ZNC::Foo($str); # OK<br />
my $num = 42;<br />
ZNC::Foo($num); # OK (only for ZNC >= 0.097)<br />
ZNC::Foo("$num"); # OK<br />
ZNC::Foo($num . ""); # OK<br />
ZNC::Foo(ZNC::String->new($num)); # OK, see below about ZNC::String<br />
<br />
If you need to ''call'' a function which gets <code>CString</code> by reference, and returns a value in it, there's a class named <code>ZNC::String</code>: <br />
<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# perl<br />
my $s = ZNC::String->new;<br />
ZNC::Foo($s);<br />
print $s->GetPerlStr; # prints 'bar' to stdout<br />
print $s; # The same, only for ZNC >= 1.7.0.<br />
<br />
As you see, to get normal string from <code>ZNC::String</code> there's a method <code>GetPerlStr</code>. Since ZNC 1.7.0 it's called automatically when string is needed.<br />
You can construct non-empty <code>ZNC::String</code> using an argument to <code>new</code>.<br />
This constructor can get string scalars, integer scalars, float scalars. <br />
<br />
When you implement a module hook which accepts <code>CString&</code>, no <code>ZNC::String</code> magic is needed, it just works: <br />
<pre><br />
sub OnChanMsg {<br />
my $self = shift;<br />
# @_ == (nick, channel, message)<br />
if ($_[0]->GetNick eq "Fish" || $_[2] eq "kwaa") {<br />
$_[2] = "moo!"<br />
}<br />
# the code above can be rewritten as follows:<br />
my ($nick, $channel, $message) = map {\$_} @_;<br />
if ($$nick->GetNick eq "Fish" || $$message eq "kwaa") {<br />
$$message = "moo!";<br />
}<br />
# alternatively, use \shift<br />
}<br />
</pre><br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
my $num_msg = $msg->As('CNumericMessage');<br />
</pre><br />
<br />
=== Module's NV ===<br />
There're some issues with using std iterators from perl, so class <code>CModule</code> got new methods: <code>GetNVKeys</code> which returns list of names of all NV values of the module, and <code>ExistsNV</code> which checks if specified variable exists. <br />
<pre><br />
sub OnModCommand {<br />
my $self = shift;<br />
my @nvkeys = $self->GetNVKeys;<br />
if ($self->ExistsNV("foo")) {<br />
$self->SetNV("bar", $self->GetNV("foo"));<br />
$self->DelNV("foo");<br />
}<br />
....<br />
}<br />
</pre><br />
Also there's another interface for accessing NVs - perl hash. (But for big number of values it's slow) <br />
<pre><br />
sub OnModCommand {<br />
my $self = shift;<br />
my $nv = $self->NV;<br />
while (my ($key, $value) = each %$nv) {<br />
...<br />
}<br />
my @nvkeys = keys %$nv;<br />
$nv->{foo} = "bar";<br />
$self->PutModule($nv->{foo});<br />
delete $nv->{foo};<br />
}<br />
</pre><br />
Of course, you can use $self->{foo} for storing temporary values, but NV data is stored on disk.<br />
<br />
=== IRCv3 server-dependent capabilities ===<br />
<br />
Available since ZNC 1.9.<br />
<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>$self->AddServerDependentCapability()</code> accepts two code references:<br />
<br />
sub OnLoad {<br />
my $self = shift;<br />
$self->AddServerDependentCapability('testcap', sub {<br />
my ($ircnetwork, $state) = @_;<br />
$self->PutModule('Server changed support: ' . ($state ? 'true' : 'false'));<br />
}, sub {<br />
my ($client, $state) = @_;<br />
$self->PutModule('Client changed support: ' . ($state ? 'true' : 'false'));<br />
});<br />
return 1;<br />
}<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module. <br />
sub GetWebMenuTitle {<br />
"Perl test module"<br />
}<br />
==== CTemplate ====<br />
<br />
Instead of operator[] use set:<br />
<pre><br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
</pre><br />
<pre><br />
# perl equivalent<br />
my $tmpl = ...;<br />
$tmpl->set("name", "value");<br />
my $row = $tmpl->AddRow("SomeTable");<br />
$row->set("foo", "bar");<br />
</pre><br />
==== Subpages ====<br />
If you want to have subpages for the module, use helper function <code>ZNC::CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional named arguments: <br />
* title - text for displaying subpage name. By default it's the same as name. <br />
* params - reference to hash of parameters which will be used in URL linking to the subpage. <br />
* admin - set to true value if subpage should be accessible only by admins. <br />
<br />
There're 2 ways: using <code>AddSubPage</code>/<code>ClearSubPages</code> and overriding <code>GetSubPages</code>. <br />
<pre><br />
sub OnLoad {<br />
my $self = shift;<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page1'));<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page2', title=>'Page N2'));<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page3', params=>{var1=>'value1', var2=>'value2'}, admin=>1);<br />
1<br />
}<br />
</pre><br />
The second way - to override <code>GetSubPages</code>. Perhaps(?) it may be better if list of subpages changes often in runtime. <br />
<br />
But don't return pointer to local variable! Perl destroys objects when reference count goes to zero. In these 2 examples additional reference to returned object is stored in <code>$self->{webpages}</code>. <br />
<pre><br />
sub OnLoad {<br />
my $self = shift;<br />
$self->{webpages} = ZNC::VWebSubPages->new;<br />
1<br />
}<br />
sub OnModCommand {<br />
my $self = shift;<br />
my $cmd = shift;<br />
$self->{webpages}->push(ZNC::CreateWebSubPage($cmd));<br />
}<br />
sub GetSubPages {<br />
my $self = shift;<br />
return $self->{webpages}<br />
}<br />
</pre><br />
<pre><br />
sub GetSubPages {<br />
my $self = shift;<br />
my $result = ZNC::VWebSubPages->new;<br />
$result->push(ZNC::CreateWebSubPage('foo'));<br />
$self->{webpages} = $result;<br />
return $result;<br />
}<br />
</pre><br />
<br />
=== Timers ===<br />
There're 2 APIs: first uses references to subs, second uses OOP packages. <br />
==== Ref API ====<br />
<br />
Use helper function <code>CreateTimer</code>.<br />
It gets following named arguments: <br />
* task ''(required)'' - Reference to a sub which will be called. The sub gets reference to your module as first argument, and ''context'' as named argument. <br />
* interval - Interval between calls, in seconds. Default is 10. <br />
* cycles - Number of times to run the sub. 0 means infinite. Default is 1. <br />
* description - Text description of the timer. Default doesn't matter. <br />
* label ''(overrideable since ZNC 1.9)'' - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default value is <code>perl-timer</code>.<br />
* context - Arbitrary value, which ''task'' will get as named argument context. <br />
<pre><br />
sub foo {<br />
my $self = shift;<br />
my %arg = @_;<br />
$self->PutStatus("foo ".$arg{context});<br />
}<br />
sub OnModCommand {<br />
my $self = shift;<br />
$self->CreateTimer(task=>\&foo, interval=>5, context=>'bar',<br />
description=>"Timer which puts 'foo bar' to status in 5 secs after user wrote something to the module");<br />
$self->CreateTimer(task=>sub {}, cycles=>0, interval=>1, description=>"Timer which every 1 second does nothing");<br />
}<br />
</pre><br />
==== OOP API ====<br />
''(available since ZNC 0.097) ''<br />
<br />
Use helper function <code>CreateTimer</code>. It gets following named arguments: <br />
* task ''(required)'' - name of your Timer class. It should be derived from <code>ZNC::Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>. <br />
* interval - Interval between calls, in seconds. Default is 10. <br />
* cycles - Number of times to run the sub. 0 means infinite. Default is 1. <br />
* description - Text description of the timer. Default doesn't matter. <br />
* label ''(overrideable since ZNC 1.9)'' - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default value is <code>perl-timer</code>.<br />
<pre><br />
# timerooptest.pm<br />
use strict;<br />
use warnings;<br />
<br />
package timerooptest::timer;<br />
use base 'ZNC::Timer';<br />
sub RunJob {<br />
my $self = shift;<br />
$self->GetModule->PutStatus('foo '.$self->{msg});<br />
}<br />
<br />
package timerooptest;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my $self = shift;<br />
my $timer = $self->CreateTimer(task=>'timerooptest::timer', interval=>4, cycles=>1,<br />
description=>'Says "foo bar" after 4 seconds');<br />
$timer->{msg} = 'bar';<br />
}<br />
</pre><br />
You can use methods of C++ class <code>CTimer</code> (like Stop) for your timer.<br />
<br />
=== Sockets ===<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special functions, which return true scalar if the feature is supported. <br />
<pre><br />
if (ZNC::HaveIPv6) {<br />
...<br />
}<br />
if (ZNC::HaveSSL) {<br />
...<br />
}<br />
if (ZNC::HaveCAres) {<br />
...<br />
}<br />
</pre><br />
All sockets are instances of special classes derived from <code>ZNC::Socket</code>.<br />
<code>ZNC::Socket</code> has all the same methods as <code>Csock</code>, except <code>Connect</code> and <code>Listen</code>.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to the associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of <code>Csock</code>, they are described later.<br />
<br />
To create socket, use module's method <code>CreateSocket</code>.<br />
First argument is the name of your socket class.<br />
The function creates socket and calls method <code>Init</code> of it with the rest of arguments.<br />
Reference to the new socket is returned. <br />
<br />
To connect socket, use method <code>Connect</code>.<br />
It gets 2 required arguments - hostname and port, and several optional named arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60. <br />
* ssl - Whether to use SSL for connection. <br />
* bindhost - Local interface to use for the connection. <br />
<br />
Returns true value if connection scheduled successfully.<br />
<pre><br />
# testmodule.pm<br />
<br />
package testmodule::connsock;<br />
use base 'ZNC::Socket';<br />
sub Init {<br />
my $self = shift;<br />
my $line = shift; # this and following arguments can be specified in CreateSocket<br />
$self->Connect('google.com', 80);<br />
$self->EnableReadLine;<br />
$self->Write("$line\r\n");<br />
}<br />
sub OnReadLine {<br />
my ($self, $line) = @_;<br />
$line =~ s/[\r\n]//g;<br />
$self->GetModule->PutStatus($line);<br />
}<br />
<br />
package testmodule;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my ($self, $cmd) = @_;<br />
my $sock = $self->CreateSocket('testmodule::connsock', "GET $cmd HTTP/1.0\r\n");<br />
}<br />
<br />
1;<br />
</pre><br />
<pre><br />
# testmodule2.pm<br />
<br />
package testmodule2::conn;<br />
use base 'ZNC::Socket';<br />
sub OnReadLine {<br />
my ($self, $line) = @_;<br />
$line =~ s/[\r\n]//g;<br />
$self->GetModule->PutStatus($line);<br />
}<br />
<br />
package testmodule2;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my ($self, $cmd) = @_;<br />
my $sock = $self->CreateSocket('testmodule2::connsock');<br />
$sock->Connect('google.com', 443, ssl=>1);<br />
$sock->EnableReadLine;<br />
$sock->Write("GET $cmd HTTP/1.0\r\n\r\n");<br />
}<br />
<br />
1;<br />
</pre><br />
<br />
To create listening socket, use method <code>Listen</code>.<br />
It gets following optional named arguments: <br />
* port - Port number to listen on. If not presented, random port is choosed. <br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces. <br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all. <br />
* ssl - Whether to use SSL for incoming connections. <br />
* maxconns - Maximum number of connections. Default is SOMAXCONN. <br />
* timeout - time in seconds, for timeout. <br />
<br />
Returns 0 on error and port number on success. <br />
<pre><br />
# testmodule3.pm<br />
<br />
package testmodule3::listensock;<br />
use base 'ZNC::Socket';<br />
sub OnAccepted {<br />
my ($self, $host, $port) = @_;<br />
$self->GetModule->CreateSocket('testmodule3::accepted', $host, $port);<br />
}<br />
<br />
package testmodule3::accepted;<br />
use base 'ZNC::Socket';<br />
sub Init {<br />
my ($self, $host, $port) = @_;<br />
$self->Write("Hello, $host:$port!\n");<br />
}<br />
sub OnReadData {<br />
my $self = shift;<br />
my ($data, $len) = @_;<br />
$self->Write($data, $len); # echo back everything<br />
}<br />
<br />
package testmodule3;<br />
use base 'ZNC::Module';<br />
sub OnLoad {<br />
my $self = shift;<br />
my $sock = $self->CreateSocket('testmodule3::listensock');<br />
my $port = $sock->Listen(ssl=>1, addrtype=>'ipv6');<br />
if ($port) {<br />
$_[1] = "Listening on all IPv6 interfaces on port $port using SSL";<br />
}<br />
1<br />
}<br />
<br />
1;<br />
</pre><br />
Sockets can override following callbacks: <br />
* <code>Init</code> - is called from <code>CreateSocket</code>, first argument is reference to socket, the rest is from arguments to <code>CreateSocket</code>. <br />
* <code>OnConnected</code><br />
* <code>OnDisconnected</code><br />
* <code>OnTimeout</code><br />
* <code>OnConnectionRefused</code><br />
* <code>OnReadData</code> - gets 2 arguments (of course, excluding reference to self): data and number of bytes. <br />
* <code>OnReadLine</code> - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket. <br />
* <code>OnAccepted</code> - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return undef if you don't need the connection, or reference to new socket, which will be used for this connection. <br />
* <code>OnShutdown</code> - ''(since 0.097)'' destructor of the socket. <br />
<br />
If callback <code>On*</code> dies/croaks, the socket is closed, but if you want to close socket, use method <code>Close</code> instead. If <code>Init</code> croaks, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>ZNC::CZNC::GetTag</code> is good. <br />
ZNC::CZNC::GetTag() # Returns, for example, 'ZNC 0.097 - http://znc.sourceforge.net'<br />
<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
Since ZNC 0.097, for getting ZNC version from Perl modules, you can use following functions: <br />
ZNC::GetVersion() # For example, number 0.097<br />
ZNC::GetVersionMajor() # 0<br />
ZNC::GetVersionMinor() # 97<br />
ZNC::GetVersionExtra() # build-specific string<br />
<br />
== Perl module Examples ==<br />
Here is a listing of useful perl modules<br />
* [https://github.com/DarthGandalf/znclinker ZNC-Linker bot]<br />
* [https://github.com/draggy/znc-perl-bitlbee-facebook-rename Facebook Bitlbee Rename]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modpython&diff=3122Modpython2024-02-11T10:56:26Z<p>DarthGandalf: /* IRCv3 server-dependent capabilities */</p>
<hr />
<div>{{DISPLAYTITLE:modpython}}<br />
{{Core Module}}<br />
<br />
Modpython allows you to use modules written on python 3.<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-python, or cmake with -DWANT_PYTHON=ON.<br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed (Note: Must be => 3.0.0). If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
If for some reason you chose to compile python3 yourself, do it with --enable-shared option. If you use python from your distro (e.g. via apt-get, yum, etc), it is already compiled in the right way, no need to recompile anything.<br />
<br />
If python was compiled without this option, you may see errors like this: <code>/usr/local/lib/znc/modpython.so: undefined symbol: forkpty</code><br />
<br />
== Usage ==<br />
<br />
Loading and unloading of python3 modules is similar to C++ modules.<br />
For example, you can use <code>/znc loadmod</code> or [[webadmin]].<br />
<br />
If you unload modpython, all python modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Caveats ==<br />
* Python multithreading doesn't work properly. However you may try multiprocessing.<br />
* ZNC executes most of the operations (including Python modules) in single thread. It means you need to be careful not to block current thread, instead all your IRC connections may timeout. Webadmin will also stop working. Ideally you offload heavy operations to separate thread. Or actually to separate process, since multithreading doesn't work.<br />
<br />
== Writing new python3 modules ==<br />
=== Basics ===<br />
<br />
Every python module is file named like modulename.py (since ZNC 1.9 you can also use the package and name it modulename/__init__.py) and is located in usual modules directories (see [[Modules#Managing_Modules|here]] for details).<br />
The file '''must''' contain class with exactly the same name as the module itself.<br />
The class should be derived from <code>znc.Module</code>.<br />
<br />
# pythonexample.py<br />
<br />
import znc<br />
<br />
class pythonexample(znc.Module):<br />
description = "Example python3 module for ZNC"<br />
<br />
def OnChanMsg(self, nick, channel, message):<br />
self.PutModule("Hey, {0} said {1} on {2}".format(nick.GetNick(), message.s, channel.GetName()))<br />
return znc.CONTINUE<br />
<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in python.<br />
<br />
<code>def OnShutdown</code> is used as destructor (instead of python's __del__).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded.<br />
<br />
If a callback returns None or doesn't return anything instead of returning something (except for the <code>void</code> return type, of course), the behavior can be bizzare. Do not do this, even though sometimes it appears to work fine. In some future version this may be changed to check return types more strictly. The same goes for exceptions raised from the callback.<br />
<br />
When a module callback should return CModule::EModRet, you can use values such as <code>znc.CModule.CONTINUE</code> or just <code>znc.CONTINUE</code>.<br />
<br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for python modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user python modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
class pyusermod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule]<br />
<br />
For global modules use this:<br />
class pyglobalmod(znc.Module):<br />
module_types = [znc.CModInfo.GlobalModule]<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
class pyusernetworkmod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule, znc.CModInfo.NetworkModule]<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod pyusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the attributes like shown below:<br />
<br />
module_types = ... (see above section)<br />
description = "This module does this and that"<br />
wiki_page = "my_module"<br />
has_args = True (the default is False)<br />
args_help_text = "The arguments are foo and bar"<br />
<br />
=== Strings ===<br />
<br />
All ZNC classes are accessible from python with <code>znc.</code> prefix. The exception is CString.<br />
All uses of CString ''by value'' is transparently translated to/from python string objects.<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# python<br />
znc.Foo("bar")<br />
The same for case where you get CString by value:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(''const CString& sArgsi'', CString& sMessage);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if args == "bar":<br />
return True<br />
return False<br />
If you need to use CString ''by reference'', use class <code>znc.String</code> and its attribute <code>s</code>:<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# python<br />
x = znc.String()<br />
znc.Foo(x);<br />
print(x.s); # prints 'bar' to stdout<br />
The same if you get CString& as argument:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgsi, ''CString& sMessage'');<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
message.s = 'bar'<br />
return True<br />
<br />
'''Note''': don't try to use the string which you got in the overloaded method for calls to other methods<br />
<br />
# C++<br />
class CModule {<br />
virtual void OnFoo(CString& sMsg);<br />
void Bar(CString& sMsg); // appends "Bar" to sMsg<br />
}<br />
<br />
# python, wrong way<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
self.Bar(msg) # ZNC crashes here<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
s = znc.String()<br />
s.s = msg.s # so that old value is preserved<br />
self.Bar(s)<br />
msg.s = s.s # put result back to ''msg''<br />
<br />
So, you want to override a hook <code>void OnFoo(const CString& sBar)</code> and you actually don't want to write to <code>sBar</code>. So you probably will want to use the argument as python string. But, let's assume that in next ZNC version <code>OnFoo</code>'s signature will be changed to <code>void OnFoo(CString& sBar)</code>. This will break your module! To be on safe side, convert the argument to string with usual <code>str()</code> function. ('''Note:''' support for <code>str()</code> was added in ZNC 0.099) <br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgs, CString& sMessage);<br />
virtual EModRet OnRaw(CString& sLine);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if str(args).startswith('bar'):<br />
...<br />
def OnRaw(self, line):<br />
if str(line).startswith('bar'):<br />
...<br />
<br />
=== Booleans ===<br />
Moost booleans just work. If a callback gets <code>bool&</code> as a parameter, use this:<br />
<br />
// C++<br />
virtual EModRet OnModuleLoading(const CString& sModName, const CString& sArgs,<br />
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg);<br />
<br />
# python<br />
def OnModuleLoading(self, name, args, typ, success, retmsg):<br />
success.b = False # similar to string with its .s<br />
return znc.HALT<br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
num_msg = msg.As(znc.CNumericMessage)<br />
</pre><br />
<br />
=== Module's NV ===<br />
<br />
<code>module.nv</code> is a dict-like object, which can be used as normal dict, but stores it's data on disk. Both keys and values should be strings.<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
self.nv['bar'] = 'baz'<br />
if 'abcde' in self.nv:<br />
try:<br />
message.s = self.nv['qwerty']<br />
except KeyError:<br />
message.s = self.nv['abcde']<br />
for k, v = self.nv.items():<br />
...<br />
<br />
=== Objects ===<br />
<br />
SWIG distinguish between instances from ZNC and instances created in Python. All instances that are created during python time are garbage collected as soon they leave scope (e.g. at the end of the function or module). To move an instance to the ZNC scope, so it can be used after the lifetime of the function/module, set the special object property .thisown to 0.<br />
<br />
For example this is required if you add new user:<br />
<br />
new_user = znc.CUser(username)<br />
str_err = znc.String()<br />
if znc.CZNC.Get().AddUser(new_user, str_err):<br />
new_user.thisown = 0 # new_user won't be garbage collected at the end of the function anymore<br />
<br />
Similiar if you want to free an instance (like removing a listener), you should make sure that the memory gets garbage collected<br />
<br />
listener = ...<br />
if znc.CZNC.Get().DelListener(listener):<br />
listener.thisown = 1<br />
<br />
=== IRCv3 server-dependent capabilities ===<br />
<br />
Available since ZNC 1.9.<br />
<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>self.AddServerDependentCapability()</code> accepts two callable objects:<br />
<br />
def OnLoad(self, args, ret):<br />
def server_change(ircnetwork, state):<br />
self.PutModule('Server changed support: ' + ('true' if state else 'false'))<br />
def client_change(client, state):<br />
self.PutModule('Client changed support: ' + ('true' if state else 'false'))<br />
self.AddServerDependentCapability('testcap', server_change, client_change)<br />
return True<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module.<br />
class test(znc.Module):<br />
def GetWebMenuTitle(self):<br />
return "Python test module"<br />
<br />
==== CTemplate ====<br />
<br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
<br />
# python equivalent (0.206 and below)<br />
tmpl = ...;<br />
tmpl.set("name", "value")<br />
row = tmpl.AddRow("SomeTable")<br />
row.set("foo", "bar")<br />
<br />
# python equivalent (since 0.207)<br />
tmpl = ...;<br />
tmpl["name"] = "value"<br />
row = tmpl.AddRow("SomeTable")<br />
row["foo"] = "bar"<br />
<br />
==== Subpages ====<br />
If you want to have subpages for the module, besides the main page, use helper function <code>znc.CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional arguments:<br />
* title - text for displaying subpage name. By default it's the same as name.<br />
* params - dict of parameters which will be used in URL linking to the subpage.<br />
* admin - set to True if subpage should be accessible only by admins.<br />
<br />
def OnLoad(self, args, message):<br />
self.AddSubPage(znc.CreateWebSubPage('page1'));<br />
self.AddSubPage(znc.CreateWebSubPage('page2', title='Page N2'))<br />
self.AddSubPage(znc.CreateWebSubPage('page3', params=dict(var1='value1', var2='value2'), admin=True))<br />
return True<br />
<br />
=== Timers ===<br />
Use helper function <code>CreateTimer</code>. It gets following arguments:<br />
* timer ''(required)'' - reference to your Timer class. It should be derived from <code>znc.Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>.<br />
* interval - Interval between calls, in seconds. Default is 10.<br />
* cycles - Number of times to run the <code>RunJob</code> function. 0 means infinite. Default is 1.<br />
* description - Text description of the timer. Default doesn't matter.<br />
* label - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default is <code>pytimer</code>.<br />
# timertest.py<br />
import znc<br />
<br />
class testtimer(znc.Timer):<br />
def RunJob(self):<br />
self.GetModule().PutStatus('foo {0}'.format(self.msg))<br />
<br />
class timertest(znc.Module):<br />
def OnModCommand(self, cmd):<br />
timer = self.CreateTimer(testtimer, interval=4, cycles=1, description='Says "foo bar" after 4 seconds', label='moo')<br />
timer.msg = 'bar'<br />
<br />
You can use methods of C++ class <code>CTimer</code> (like <code>Stop</code>) for your timer.<br />
<br />
=== Sockets ===<br />
<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special variables, which are True if the feature is supported.<br />
if znc.HaveIPv6:<br />
...<br />
if znc.HaveSSL:<br />
...<br />
if znc.HaveCAres:<br />
...<br />
All sockets are instances of special classes derived from <code>znc.Socket</code>.<br />
znc.Socket has all the same methods as Csock, except Connect, Listen and Write.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of Csock, they are described later.<br />
<br />
To create socket, use module's method CreateSocket. First argument is reference to your socket class. The function creates socket and calls method <code>Init</code> of it with the rest of arguments. Reference to the new socket is returned.<br />
<br />
To connect socket, use method <code>Connect</code>. It gets 2 required arguments - hostname and port, and several optional arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60.<br />
* ssl - Whether to use SSL for connection.<br />
* bindhost - Local interface to use for the connection.<br />
Returns true value if connection scheduled successfully.<br />
<br />
# networkconn.py<br />
import znc<br />
class connsock(znc.Socket):<br />
def Init(self, line): # line and other arguments, including named arguments can be specified in CreateSocket<br />
self.Connect('google.com', 80)<br />
self.EnableReadLine()<br />
self.Write("{0}\r\n".format(line))<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line) # this puts also \n and \r to status, which is not very good, but this is just an example, so...<br />
<br />
class networkconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(connsock, "GET {0} HTTP/1.0\r\n".format(cmd))<br />
<br />
# socketconn.py<br />
import znc<br />
class conn(znc.Socket):<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line)<br />
<br />
class socketconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(conn)<br />
sock.Connect('google.com', 443, ssl=True)<br />
sock.EnableReadLine()<br />
sock.Write("GET {0} HTTP/1.0\r\n\r\n".format(cmd))<br />
<br />
To create listening socket, use method <code>Listen</code>. It gets following optional named arguments:<br />
* port - Port number to listen on. If not presented, random port is choosed.<br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces.<br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all.<br />
* ssl - Whether to use SSL for incoming connections.<br />
* maxconns - Maximum number of connections. Default is SOMAXCONN.<br />
* timeout - time in seconds, for timeout.<br />
Returns 0 on error and port number on success.<br />
# listmodule.py<br />
import znc<br />
<br />
class accepted(znc.Socket):<br />
def Init(self, host, port):<br />
self.Write("Hello, {0}:{1}!\n".format(host, port))<br />
def OnReadData(self, data):<br />
self.WriteBytes(data) # echo back everything<br />
<br />
class listensock(znc.Socket):<br />
def OnAccepted(self, host, port):<br />
return self.GetModule().CreateSocket(accepted, host, port)<br />
<br />
class listmodule(znc.Module):<br />
def OnLoad(self, args, message):<br />
sock = self.CreateSocket(listensock)<br />
port = sock.Listen(ssl=True, addrtype='ipv6');<br />
if port > 0:<br />
message.s = "Listening on all IPv6 interfaces on port {0} using SSL".format(port)<br />
return True<br />
<br />
Use <code>Write</code> to write strings, and <code>WriteBytes</code> to write binary data.<br />
<br />
Sockets can override following callbacks:<br />
* Init - is called from CreateSocket, first argument is reference to socket, the rest is from arguments to CreateSocket.<br />
* OnConnected<br />
* OnDisconnected<br />
* OnTimeout<br />
* OnConnectionRefused<br />
* OnReadData - gets bytes as second argument<br />
* OnReadLine - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket.<br />
* OnAccepted - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return None if you don't need the connection, or reference to new socket, which will be used for this connection.<br />
* OnShutdown - destructor of the socket.<br />
<br />
If callback On* raises an exception, the socket is closed, but if you want to close socket, use method <code>Close</code> instead.<br />
If Init raises an exception, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>znc.CZNC.GetTag()</code> is good.<br />
znc.CZNC.GetTag() # Returns, for example, 'ZNC 0.097 - http:/<nowiki></nowiki>/znc.sourceforge.net'<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
For getting ZNC version, you can use read following variables:<br />
znc.Version # For example, number 0.097<br />
znc.VersionMajor # 0<br />
znc.VersionMinor # 97<br />
znc.VersionExtra # build-specific string<br />
<br />
<br />
[[Category:Modules]]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modpython&diff=3121Modpython2024-02-11T10:56:07Z<p>DarthGandalf: /* IRCv3 capabilities */</p>
<hr />
<div>{{DISPLAYTITLE:modpython}}<br />
{{Core Module}}<br />
<br />
Modpython allows you to use modules written on python 3.<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-python, or cmake with -DWANT_PYTHON=ON.<br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed (Note: Must be => 3.0.0). If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
If for some reason you chose to compile python3 yourself, do it with --enable-shared option. If you use python from your distro (e.g. via apt-get, yum, etc), it is already compiled in the right way, no need to recompile anything.<br />
<br />
If python was compiled without this option, you may see errors like this: <code>/usr/local/lib/znc/modpython.so: undefined symbol: forkpty</code><br />
<br />
== Usage ==<br />
<br />
Loading and unloading of python3 modules is similar to C++ modules.<br />
For example, you can use <code>/znc loadmod</code> or [[webadmin]].<br />
<br />
If you unload modpython, all python modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Caveats ==<br />
* Python multithreading doesn't work properly. However you may try multiprocessing.<br />
* ZNC executes most of the operations (including Python modules) in single thread. It means you need to be careful not to block current thread, instead all your IRC connections may timeout. Webadmin will also stop working. Ideally you offload heavy operations to separate thread. Or actually to separate process, since multithreading doesn't work.<br />
<br />
== Writing new python3 modules ==<br />
=== Basics ===<br />
<br />
Every python module is file named like modulename.py (since ZNC 1.9 you can also use the package and name it modulename/__init__.py) and is located in usual modules directories (see [[Modules#Managing_Modules|here]] for details).<br />
The file '''must''' contain class with exactly the same name as the module itself.<br />
The class should be derived from <code>znc.Module</code>.<br />
<br />
# pythonexample.py<br />
<br />
import znc<br />
<br />
class pythonexample(znc.Module):<br />
description = "Example python3 module for ZNC"<br />
<br />
def OnChanMsg(self, nick, channel, message):<br />
self.PutModule("Hey, {0} said {1} on {2}".format(nick.GetNick(), message.s, channel.GetName()))<br />
return znc.CONTINUE<br />
<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in python.<br />
<br />
<code>def OnShutdown</code> is used as destructor (instead of python's __del__).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded.<br />
<br />
If a callback returns None or doesn't return anything instead of returning something (except for the <code>void</code> return type, of course), the behavior can be bizzare. Do not do this, even though sometimes it appears to work fine. In some future version this may be changed to check return types more strictly. The same goes for exceptions raised from the callback.<br />
<br />
When a module callback should return CModule::EModRet, you can use values such as <code>znc.CModule.CONTINUE</code> or just <code>znc.CONTINUE</code>.<br />
<br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for python modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user python modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
class pyusermod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule]<br />
<br />
For global modules use this:<br />
class pyglobalmod(znc.Module):<br />
module_types = [znc.CModInfo.GlobalModule]<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
class pyusernetworkmod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule, znc.CModInfo.NetworkModule]<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod pyusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the attributes like shown below:<br />
<br />
module_types = ... (see above section)<br />
description = "This module does this and that"<br />
wiki_page = "my_module"<br />
has_args = True (the default is False)<br />
args_help_text = "The arguments are foo and bar"<br />
<br />
=== Strings ===<br />
<br />
All ZNC classes are accessible from python with <code>znc.</code> prefix. The exception is CString.<br />
All uses of CString ''by value'' is transparently translated to/from python string objects.<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# python<br />
znc.Foo("bar")<br />
The same for case where you get CString by value:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(''const CString& sArgsi'', CString& sMessage);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if args == "bar":<br />
return True<br />
return False<br />
If you need to use CString ''by reference'', use class <code>znc.String</code> and its attribute <code>s</code>:<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# python<br />
x = znc.String()<br />
znc.Foo(x);<br />
print(x.s); # prints 'bar' to stdout<br />
The same if you get CString& as argument:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgsi, ''CString& sMessage'');<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
message.s = 'bar'<br />
return True<br />
<br />
'''Note''': don't try to use the string which you got in the overloaded method for calls to other methods<br />
<br />
# C++<br />
class CModule {<br />
virtual void OnFoo(CString& sMsg);<br />
void Bar(CString& sMsg); // appends "Bar" to sMsg<br />
}<br />
<br />
# python, wrong way<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
self.Bar(msg) # ZNC crashes here<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
s = znc.String()<br />
s.s = msg.s # so that old value is preserved<br />
self.Bar(s)<br />
msg.s = s.s # put result back to ''msg''<br />
<br />
So, you want to override a hook <code>void OnFoo(const CString& sBar)</code> and you actually don't want to write to <code>sBar</code>. So you probably will want to use the argument as python string. But, let's assume that in next ZNC version <code>OnFoo</code>'s signature will be changed to <code>void OnFoo(CString& sBar)</code>. This will break your module! To be on safe side, convert the argument to string with usual <code>str()</code> function. ('''Note:''' support for <code>str()</code> was added in ZNC 0.099) <br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgs, CString& sMessage);<br />
virtual EModRet OnRaw(CString& sLine);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if str(args).startswith('bar'):<br />
...<br />
def OnRaw(self, line):<br />
if str(line).startswith('bar'):<br />
...<br />
<br />
=== Booleans ===<br />
Moost booleans just work. If a callback gets <code>bool&</code> as a parameter, use this:<br />
<br />
// C++<br />
virtual EModRet OnModuleLoading(const CString& sModName, const CString& sArgs,<br />
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg);<br />
<br />
# python<br />
def OnModuleLoading(self, name, args, typ, success, retmsg):<br />
success.b = False # similar to string with its .s<br />
return znc.HALT<br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
num_msg = msg.As(znc.CNumericMessage)<br />
</pre><br />
<br />
=== Module's NV ===<br />
<br />
<code>module.nv</code> is a dict-like object, which can be used as normal dict, but stores it's data on disk. Both keys and values should be strings.<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
self.nv['bar'] = 'baz'<br />
if 'abcde' in self.nv:<br />
try:<br />
message.s = self.nv['qwerty']<br />
except KeyError:<br />
message.s = self.nv['abcde']<br />
for k, v = self.nv.items():<br />
...<br />
<br />
=== Objects ===<br />
<br />
SWIG distinguish between instances from ZNC and instances created in Python. All instances that are created during python time are garbage collected as soon they leave scope (e.g. at the end of the function or module). To move an instance to the ZNC scope, so it can be used after the lifetime of the function/module, set the special object property .thisown to 0.<br />
<br />
For example this is required if you add new user:<br />
<br />
new_user = znc.CUser(username)<br />
str_err = znc.String()<br />
if znc.CZNC.Get().AddUser(new_user, str_err):<br />
new_user.thisown = 0 # new_user won't be garbage collected at the end of the function anymore<br />
<br />
Similiar if you want to free an instance (like removing a listener), you should make sure that the memory gets garbage collected<br />
<br />
listener = ...<br />
if znc.CZNC.Get().DelListener(listener):<br />
listener.thisown = 1<br />
<br />
=== IRCv3 server-dependent capabilities ===<br />
<br />
Available since ZNC 1.9.<br />
<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>self.AddServerDependentCapability()</code> accepts two callable objects:<br />
<br />
def OnLoad(self, args, ret):<br />
def server_change(ircnetwork, state):<br />
self.PutModule('Server changed support: ' + ('true' if state else 'false'))<br />
def client_change(client, state):<br />
self.PutModule('Client changed support: ' + ('true' if state else 'false'))<br />
self.AddServerDependentCapability('testcap', server_change, client_change)<br />
return True<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module.<br />
class test(znc.Module):<br />
def GetWebMenuTitle(self):<br />
return "Python test module"<br />
<br />
==== CTemplate ====<br />
<br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
<br />
# python equivalent (0.206 and below)<br />
tmpl = ...;<br />
tmpl.set("name", "value")<br />
row = tmpl.AddRow("SomeTable")<br />
row.set("foo", "bar")<br />
<br />
# python equivalent (since 0.207)<br />
tmpl = ...;<br />
tmpl["name"] = "value"<br />
row = tmpl.AddRow("SomeTable")<br />
row["foo"] = "bar"<br />
<br />
==== Subpages ====<br />
If you want to have subpages for the module, besides the main page, use helper function <code>znc.CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional arguments:<br />
* title - text for displaying subpage name. By default it's the same as name.<br />
* params - dict of parameters which will be used in URL linking to the subpage.<br />
* admin - set to True if subpage should be accessible only by admins.<br />
<br />
def OnLoad(self, args, message):<br />
self.AddSubPage(znc.CreateWebSubPage('page1'));<br />
self.AddSubPage(znc.CreateWebSubPage('page2', title='Page N2'))<br />
self.AddSubPage(znc.CreateWebSubPage('page3', params=dict(var1='value1', var2='value2'), admin=True))<br />
return True<br />
<br />
=== Timers ===<br />
Use helper function <code>CreateTimer</code>. It gets following arguments:<br />
* timer ''(required)'' - reference to your Timer class. It should be derived from <code>znc.Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>.<br />
* interval - Interval between calls, in seconds. Default is 10.<br />
* cycles - Number of times to run the <code>RunJob</code> function. 0 means infinite. Default is 1.<br />
* description - Text description of the timer. Default doesn't matter.<br />
* label - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default is <code>pytimer</code>.<br />
# timertest.py<br />
import znc<br />
<br />
class testtimer(znc.Timer):<br />
def RunJob(self):<br />
self.GetModule().PutStatus('foo {0}'.format(self.msg))<br />
<br />
class timertest(znc.Module):<br />
def OnModCommand(self, cmd):<br />
timer = self.CreateTimer(testtimer, interval=4, cycles=1, description='Says "foo bar" after 4 seconds', label='moo')<br />
timer.msg = 'bar'<br />
<br />
You can use methods of C++ class <code>CTimer</code> (like <code>Stop</code>) for your timer.<br />
<br />
=== Sockets ===<br />
<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special variables, which are True if the feature is supported.<br />
if znc.HaveIPv6:<br />
...<br />
if znc.HaveSSL:<br />
...<br />
if znc.HaveCAres:<br />
...<br />
All sockets are instances of special classes derived from <code>znc.Socket</code>.<br />
znc.Socket has all the same methods as Csock, except Connect, Listen and Write.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of Csock, they are described later.<br />
<br />
To create socket, use module's method CreateSocket. First argument is reference to your socket class. The function creates socket and calls method <code>Init</code> of it with the rest of arguments. Reference to the new socket is returned.<br />
<br />
To connect socket, use method <code>Connect</code>. It gets 2 required arguments - hostname and port, and several optional arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60.<br />
* ssl - Whether to use SSL for connection.<br />
* bindhost - Local interface to use for the connection.<br />
Returns true value if connection scheduled successfully.<br />
<br />
# networkconn.py<br />
import znc<br />
class connsock(znc.Socket):<br />
def Init(self, line): # line and other arguments, including named arguments can be specified in CreateSocket<br />
self.Connect('google.com', 80)<br />
self.EnableReadLine()<br />
self.Write("{0}\r\n".format(line))<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line) # this puts also \n and \r to status, which is not very good, but this is just an example, so...<br />
<br />
class networkconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(connsock, "GET {0} HTTP/1.0\r\n".format(cmd))<br />
<br />
# socketconn.py<br />
import znc<br />
class conn(znc.Socket):<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line)<br />
<br />
class socketconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(conn)<br />
sock.Connect('google.com', 443, ssl=True)<br />
sock.EnableReadLine()<br />
sock.Write("GET {0} HTTP/1.0\r\n\r\n".format(cmd))<br />
<br />
To create listening socket, use method <code>Listen</code>. It gets following optional named arguments:<br />
* port - Port number to listen on. If not presented, random port is choosed.<br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces.<br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all.<br />
* ssl - Whether to use SSL for incoming connections.<br />
* maxconns - Maximum number of connections. Default is SOMAXCONN.<br />
* timeout - time in seconds, for timeout.<br />
Returns 0 on error and port number on success.<br />
# listmodule.py<br />
import znc<br />
<br />
class accepted(znc.Socket):<br />
def Init(self, host, port):<br />
self.Write("Hello, {0}:{1}!\n".format(host, port))<br />
def OnReadData(self, data):<br />
self.WriteBytes(data) # echo back everything<br />
<br />
class listensock(znc.Socket):<br />
def OnAccepted(self, host, port):<br />
return self.GetModule().CreateSocket(accepted, host, port)<br />
<br />
class listmodule(znc.Module):<br />
def OnLoad(self, args, message):<br />
sock = self.CreateSocket(listensock)<br />
port = sock.Listen(ssl=True, addrtype='ipv6');<br />
if port > 0:<br />
message.s = "Listening on all IPv6 interfaces on port {0} using SSL".format(port)<br />
return True<br />
<br />
Use <code>Write</code> to write strings, and <code>WriteBytes</code> to write binary data.<br />
<br />
Sockets can override following callbacks:<br />
* Init - is called from CreateSocket, first argument is reference to socket, the rest is from arguments to CreateSocket.<br />
* OnConnected<br />
* OnDisconnected<br />
* OnTimeout<br />
* OnConnectionRefused<br />
* OnReadData - gets bytes as second argument<br />
* OnReadLine - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket.<br />
* OnAccepted - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return None if you don't need the connection, or reference to new socket, which will be used for this connection.<br />
* OnShutdown - destructor of the socket.<br />
<br />
If callback On* raises an exception, the socket is closed, but if you want to close socket, use method <code>Close</code> instead.<br />
If Init raises an exception, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>znc.CZNC.GetTag()</code> is good.<br />
znc.CZNC.GetTag() # Returns, for example, 'ZNC 0.097 - http:/<nowiki></nowiki>/znc.sourceforge.net'<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
For getting ZNC version, you can use read following variables:<br />
znc.Version # For example, number 0.097<br />
znc.VersionMajor # 0<br />
znc.VersionMinor # 97<br />
znc.VersionExtra # build-specific string<br />
<br />
<br />
[[Category:Modules]]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modperl&diff=3120Modperl2024-02-11T10:56:02Z<p>DarthGandalf: /* IRCv3 capabilities */</p>
<hr />
<div>{{DISPLAYTITLE:modperl}}<br />
{{Core Module}}<br />
<br />
Modperl allows you to use modules written on perl. <br />
<br />
This page describes module since ZNC 0.095. If you still need help on old modperl, look [[Modperl/old|here]].<br />
<br />
__TOC__<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-perl or cmake with -DWANT_PERL=ON. <br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed. If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
== Usage ==<br />
Loading and unloading of perl modules is similar to C++ modules. For example, you can use <code>/znc loadmod</code> or [[webadmin]]. <br />
<br />
If you unload modperl, all perl modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Writing new perl modules ==<br />
=== Basics ===<br />
<br />
Every perl module is file named like <code>modulename.pm</code> and is located in usual modules directories.<br />
The file must contain package with exactly the same name as the module itself.<br />
The module should be derived from <code>ZNC::Module</code>. <br />
<pre><br />
# perlexample.pm<br />
<br />
package perlexample;<br />
use base 'ZNC::Module';<br />
<br />
sub description {<br />
"Example perl module for ZNC"<br />
}<br />
<br />
sub OnChanMsg {<br />
my $self = shift;<br />
my ($nick, $chan, $msg) = @_;<br />
$self->PutModule("Hey, ".$nick->GetNick." said [$msg] on ".$chan->GetName);<br />
return $ZNC::CONTINUE;<br />
}<br />
<br />
1;<br />
</pre><br />
If you want to define several perl packages inside your module, you should name them as subpackages of your module package.<br />
See [[#Sockets|Sockets]] section for example. <br />
<br />
Description of the module is the return value from a <code>sub description</code>.<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in perl.<br />
The exception is callbacks which get vector<...> as last argument:<br />
<pre><br />
virtual void OnQuit(const CNick& Nick, const CString& sMessage, ''const vector<CChan*>& vChans'');<br />
</pre><br />
<pre><br />
sub OnQuit {<br />
my ($self, $nick, $message, ''@chans'') = @_;<br />
for (@chans) {<br />
$self->PutIRC("PRIVMSG ".$_->GetName." :Poor ".$nick->GetNick." :(");<br />
}<br />
}<br />
</pre><br />
<code>sub OnShutdown</code> is used as destructor (instead of perl's <code>DESTROY</code>).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded. <br />
<br />
If a callback returns undef, a reasonable default is substituted.<br />
Remember that if execution comes to end of sub, last evaluated value is returned!<br />
If a callback dies/croaks, the default value is assumed too, the behavior of what happens to arguments is undefined.<br />
When a module callback should return <code>CModule::EModRet</code>, you can use values as <code>$ZNC::CModule::CONTINUE</code> or just <code>$ZNC::CONTINUE</code>. <br />
<br />
Don't begin names of your member data fields with underscore (_) - some of them are used by modperl internally. <br />
<pre><br />
sub OnShutdown {<br />
my $self = shift;<br />
$self->{foo} = "foo"; # OK<br />
$self->{_bar} = "bar"; # Fail, probably will work but can randomly stop working.<br />
}<br />
</pre><br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for perl modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user perl modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
package perlusermod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::UserModule }<br />
<br />
For global modules use this:<br />
package perlglobalmod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::GlobalModule }<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
package perlusernetworkmod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::UserModule, $ZNC::CModInfo::NetworkModule }<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod perlusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the functions like shown below:<br />
<br />
sub module_types { ... (see above section) }<br />
sub description { "This module does this and that" }<br />
sub wiki_page { "my_module" }<br />
sub has_args { 1 } # the default is 0<br />
sub args_help_text { "The arguments are foo and bar" }<br />
<br />
=== Strings ===<br />
All ZNC classes are accessible from perl with <code>ZNC::</code> prefix.<br />
The exception is <code>CString</code>. All uses of <code>CString</code> by value are transparently translated to/from perl string scalars. <br />
<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# perl<br />
my $str = "bar";<br />
ZNC::Foo($str); # OK<br />
my $num = 42;<br />
ZNC::Foo($num); # OK (only for ZNC >= 0.097)<br />
ZNC::Foo("$num"); # OK<br />
ZNC::Foo($num . ""); # OK<br />
ZNC::Foo(ZNC::String->new($num)); # OK, see below about ZNC::String<br />
<br />
If you need to ''call'' a function which gets <code>CString</code> by reference, and returns a value in it, there's a class named <code>ZNC::String</code>: <br />
<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# perl<br />
my $s = ZNC::String->new;<br />
ZNC::Foo($s);<br />
print $s->GetPerlStr; # prints 'bar' to stdout<br />
print $s; # The same, only for ZNC >= 1.7.0.<br />
<br />
As you see, to get normal string from <code>ZNC::String</code> there's a method <code>GetPerlStr</code>. Since ZNC 1.7.0 it's called automatically when string is needed.<br />
You can construct non-empty <code>ZNC::String</code> using an argument to <code>new</code>.<br />
This constructor can get string scalars, integer scalars, float scalars. <br />
<br />
When you implement a module hook which accepts <code>CString&</code>, no <code>ZNC::String</code> magic is needed, it just works: <br />
<pre><br />
sub OnChanMsg {<br />
my $self = shift;<br />
# @_ == (nick, channel, message)<br />
if ($_[0]->GetNick eq "Fish" || $_[2] eq "kwaa") {<br />
$_[2] = "moo!"<br />
}<br />
# the code above can be rewritten as follows:<br />
my ($nick, $channel, $message) = map {\$_} @_;<br />
if ($$nick->GetNick eq "Fish" || $$message eq "kwaa") {<br />
$$message = "moo!";<br />
}<br />
# alternatively, use \shift<br />
}<br />
</pre><br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
my $num_msg = $msg->As('CNumericMessage');<br />
</pre><br />
<br />
=== Module's NV ===<br />
There're some issues with using std iterators from perl, so class <code>CModule</code> got new methods: <code>GetNVKeys</code> which returns list of names of all NV values of the module, and <code>ExistsNV</code> which checks if specified variable exists. <br />
<pre><br />
sub OnModCommand {<br />
my $self = shift;<br />
my @nvkeys = $self->GetNVKeys;<br />
if ($self->ExistsNV("foo")) {<br />
$self->SetNV("bar", $self->GetNV("foo"));<br />
$self->DelNV("foo");<br />
}<br />
....<br />
}<br />
</pre><br />
Also there's another interface for accessing NVs - perl hash. (But for big number of values it's slow) <br />
<pre><br />
sub OnModCommand {<br />
my $self = shift;<br />
my $nv = $self->NV;<br />
while (my ($key, $value) = each %$nv) {<br />
...<br />
}<br />
my @nvkeys = keys %$nv;<br />
$nv->{foo} = "bar";<br />
$self->PutModule($nv->{foo});<br />
delete $nv->{foo};<br />
}<br />
</pre><br />
Of course, you can use $self->{foo} for storing temporary values, but NV data is stored on disk.<br />
<br />
=== IRCv3 server-dependent capabilities ===<br />
<br />
Available since ZNC 1.9.<br />
<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>$self->AddServerDependentCapability()</code> accepts two code references:<br />
<br />
sub OnLoad {<br />
my $self = shift;<br />
$self->AddServerDependentCapability('testcap', sub {<br />
my ($ircnetwork, $state) = @_;<br />
$self->PutModule('Server changed support: ' . ($state ? 'true' : 'false'));<br />
}, sub {<br />
my ($client, $state) = @_;<br />
$self->PutModule('Client changed support: ' . ($state ? 'true' : 'false'));<br />
});<br />
return 1;<br />
}<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module. <br />
sub GetWebMenuTitle {<br />
"Perl test module"<br />
}<br />
==== CTemplate ====<br />
<br />
Instead of operator[] use set:<br />
<pre><br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
</pre><br />
<pre><br />
# perl equivalent<br />
my $tmpl = ...;<br />
$tmpl->set("name", "value");<br />
my $row = $tmpl->AddRow("SomeTable");<br />
$row->set("foo", "bar");<br />
</pre><br />
==== Subpages ====<br />
If you want to have subpages for the module, use helper function <code>ZNC::CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional named arguments: <br />
* title - text for displaying subpage name. By default it's the same as name. <br />
* params - reference to hash of parameters which will be used in URL linking to the subpage. <br />
* admin - set to true value if subpage should be accessible only by admins. <br />
<br />
There're 2 ways: using <code>AddSubPage</code>/<code>ClearSubPages</code> and overriding <code>GetSubPages</code>. <br />
<pre><br />
sub OnLoad {<br />
my $self = shift;<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page1'));<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page2', title=>'Page N2'));<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page3', params=>{var1=>'value1', var2=>'value2'}, admin=>1);<br />
1<br />
}<br />
</pre><br />
The second way - to override <code>GetSubPages</code>. Perhaps(?) it may be better if list of subpages changes often in runtime. <br />
<br />
But don't return pointer to local variable! Perl destroys objects when reference count goes to zero. In these 2 examples additional reference to returned object is stored in <code>$self->{webpages}</code>. <br />
<pre><br />
sub OnLoad {<br />
my $self = shift;<br />
$self->{webpages} = ZNC::VWebSubPages->new;<br />
1<br />
}<br />
sub OnModCommand {<br />
my $self = shift;<br />
my $cmd = shift;<br />
$self->{webpages}->push(ZNC::CreateWebSubPage($cmd));<br />
}<br />
sub GetSubPages {<br />
my $self = shift;<br />
return $self->{webpages}<br />
}<br />
</pre><br />
<pre><br />
sub GetSubPages {<br />
my $self = shift;<br />
my $result = ZNC::VWebSubPages->new;<br />
$result->push(ZNC::CreateWebSubPage('foo'));<br />
$self->{webpages} = $result;<br />
return $result;<br />
}<br />
</pre><br />
<br />
=== Timers ===<br />
There're 2 APIs: first uses references to subs, second uses OOP packages. <br />
==== Ref API ====<br />
<br />
Use helper function <code>CreateTimer</code>.<br />
It gets following named arguments: <br />
* task ''(required)'' - Reference to a sub which will be called. The sub gets reference to your module as first argument, and ''context'' as named argument. <br />
* interval - Interval between calls, in seconds. Default is 10. <br />
* cycles - Number of times to run the sub. 0 means infinite. Default is 1. <br />
* description - Text description of the timer. Default doesn't matter. <br />
* label ''(overrideable since ZNC 1.9)'' - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default value is <code>perl-timer</code>.<br />
* context - Arbitrary value, which ''task'' will get as named argument context. <br />
<pre><br />
sub foo {<br />
my $self = shift;<br />
my %arg = @_;<br />
$self->PutStatus("foo ".$arg{context});<br />
}<br />
sub OnModCommand {<br />
my $self = shift;<br />
$self->CreateTimer(task=>\&foo, interval=>5, context=>'bar',<br />
description=>"Timer which puts 'foo bar' to status in 5 secs after user wrote something to the module");<br />
$self->CreateTimer(task=>sub {}, cycles=>0, interval=>1, description=>"Timer which every 1 second does nothing");<br />
}<br />
</pre><br />
==== OOP API ====<br />
''(available since ZNC 0.097) ''<br />
<br />
Use helper function <code>CreateTimer</code>. It gets following named arguments: <br />
* task ''(required)'' - name of your Timer class. It should be derived from <code>ZNC::Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>. <br />
* interval - Interval between calls, in seconds. Default is 10. <br />
* cycles - Number of times to run the sub. 0 means infinite. Default is 1. <br />
* description - Text description of the timer. Default doesn't matter. <br />
* label ''(overrideable since ZNC 1.9)'' - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default value is <code>perl-timer</code>.<br />
<pre><br />
# timerooptest.pm<br />
use strict;<br />
use warnings;<br />
<br />
package timerooptest::timer;<br />
use base 'ZNC::Timer';<br />
sub RunJob {<br />
my $self = shift;<br />
$self->GetModule->PutStatus('foo '.$self->{msg});<br />
}<br />
<br />
package timerooptest;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my $self = shift;<br />
my $timer = $self->CreateTimer(task=>'timerooptest::timer', interval=>4, cycles=>1,<br />
description=>'Says "foo bar" after 4 seconds');<br />
$timer->{msg} = 'bar';<br />
}<br />
</pre><br />
You can use methods of C++ class <code>CTimer</code> (like Stop) for your timer.<br />
<br />
=== Sockets ===<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special functions, which return true scalar if the feature is supported. <br />
<pre><br />
if (ZNC::HaveIPv6) {<br />
...<br />
}<br />
if (ZNC::HaveSSL) {<br />
...<br />
}<br />
if (ZNC::HaveCAres) {<br />
...<br />
}<br />
</pre><br />
All sockets are instances of special classes derived from <code>ZNC::Socket</code>.<br />
<code>ZNC::Socket</code> has all the same methods as <code>Csock</code>, except <code>Connect</code> and <code>Listen</code>.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to the associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of <code>Csock</code>, they are described later.<br />
<br />
To create socket, use module's method <code>CreateSocket</code>.<br />
First argument is the name of your socket class.<br />
The function creates socket and calls method <code>Init</code> of it with the rest of arguments.<br />
Reference to the new socket is returned. <br />
<br />
To connect socket, use method <code>Connect</code>.<br />
It gets 2 required arguments - hostname and port, and several optional named arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60. <br />
* ssl - Whether to use SSL for connection. <br />
* bindhost - Local interface to use for the connection. <br />
<br />
Returns true value if connection scheduled successfully.<br />
<pre><br />
# testmodule.pm<br />
<br />
package testmodule::connsock;<br />
use base 'ZNC::Socket';<br />
sub Init {<br />
my $self = shift;<br />
my $line = shift; # this and following arguments can be specified in CreateSocket<br />
$self->Connect('google.com', 80);<br />
$self->EnableReadLine;<br />
$self->Write("$line\r\n");<br />
}<br />
sub OnReadLine {<br />
my ($self, $line) = @_;<br />
$line =~ s/[\r\n]//g;<br />
$self->GetModule->PutStatus($line);<br />
}<br />
<br />
package testmodule;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my ($self, $cmd) = @_;<br />
my $sock = $self->CreateSocket('testmodule::connsock', "GET $cmd HTTP/1.0\r\n");<br />
}<br />
<br />
1;<br />
</pre><br />
<pre><br />
# testmodule2.pm<br />
<br />
package testmodule2::conn;<br />
use base 'ZNC::Socket';<br />
sub OnReadLine {<br />
my ($self, $line) = @_;<br />
$line =~ s/[\r\n]//g;<br />
$self->GetModule->PutStatus($line);<br />
}<br />
<br />
package testmodule2;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my ($self, $cmd) = @_;<br />
my $sock = $self->CreateSocket('testmodule2::connsock');<br />
$sock->Connect('google.com', 443, ssl=>1);<br />
$sock->EnableReadLine;<br />
$sock->Write("GET $cmd HTTP/1.0\r\n\r\n");<br />
}<br />
<br />
1;<br />
</pre><br />
<br />
To create listening socket, use method <code>Listen</code>.<br />
It gets following optional named arguments: <br />
* port - Port number to listen on. If not presented, random port is choosed. <br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces. <br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all. <br />
* ssl - Whether to use SSL for incoming connections. <br />
* maxconns - Maximum number of connections. Default is SOMAXCONN. <br />
* timeout - time in seconds, for timeout. <br />
<br />
Returns 0 on error and port number on success. <br />
<pre><br />
# testmodule3.pm<br />
<br />
package testmodule3::listensock;<br />
use base 'ZNC::Socket';<br />
sub OnAccepted {<br />
my ($self, $host, $port) = @_;<br />
$self->GetModule->CreateSocket('testmodule3::accepted', $host, $port);<br />
}<br />
<br />
package testmodule3::accepted;<br />
use base 'ZNC::Socket';<br />
sub Init {<br />
my ($self, $host, $port) = @_;<br />
$self->Write("Hello, $host:$port!\n");<br />
}<br />
sub OnReadData {<br />
my $self = shift;<br />
my ($data, $len) = @_;<br />
$self->Write($data, $len); # echo back everything<br />
}<br />
<br />
package testmodule3;<br />
use base 'ZNC::Module';<br />
sub OnLoad {<br />
my $self = shift;<br />
my $sock = $self->CreateSocket('testmodule3::listensock');<br />
my $port = $sock->Listen(ssl=>1, addrtype=>'ipv6');<br />
if ($port) {<br />
$_[1] = "Listening on all IPv6 interfaces on port $port using SSL";<br />
}<br />
1<br />
}<br />
<br />
1;<br />
</pre><br />
Sockets can override following callbacks: <br />
* <code>Init</code> - is called from <code>CreateSocket</code>, first argument is reference to socket, the rest is from arguments to <code>CreateSocket</code>. <br />
* <code>OnConnected</code><br />
* <code>OnDisconnected</code><br />
* <code>OnTimeout</code><br />
* <code>OnConnectionRefused</code><br />
* <code>OnReadData</code> - gets 2 arguments (of course, excluding reference to self): data and number of bytes. <br />
* <code>OnReadLine</code> - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket. <br />
* <code>OnAccepted</code> - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return undef if you don't need the connection, or reference to new socket, which will be used for this connection. <br />
* <code>OnShutdown</code> - ''(since 0.097)'' destructor of the socket. <br />
<br />
If callback <code>On*</code> dies/croaks, the socket is closed, but if you want to close socket, use method <code>Close</code> instead. If <code>Init</code> croaks, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>ZNC::CZNC::GetTag</code> is good. <br />
ZNC::CZNC::GetTag() # Returns, for example, 'ZNC 0.097 - http://znc.sourceforge.net'<br />
<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
Since ZNC 0.097, for getting ZNC version from Perl modules, you can use following functions: <br />
ZNC::GetVersion() # For example, number 0.097<br />
ZNC::GetVersionMajor() # 0<br />
ZNC::GetVersionMinor() # 97<br />
ZNC::GetVersionExtra() # build-specific string<br />
<br />
== Perl module Examples ==<br />
Here is a listing of useful perl modules<br />
* [https://github.com/DarthGandalf/znclinker ZNC-Linker bot]<br />
* [https://github.com/draggy/znc-perl-bitlbee-facebook-rename Facebook Bitlbee Rename]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modperl&diff=3119Modperl2024-02-11T09:41:49Z<p>DarthGandalf: /* Web */</p>
<hr />
<div>{{DISPLAYTITLE:modperl}}<br />
{{Core Module}}<br />
<br />
Modperl allows you to use modules written on perl. <br />
<br />
This page describes module since ZNC 0.095. If you still need help on old modperl, look [[Modperl/old|here]].<br />
<br />
__TOC__<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-perl or cmake with -DWANT_PERL=ON. <br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed. If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
== Usage ==<br />
Loading and unloading of perl modules is similar to C++ modules. For example, you can use <code>/znc loadmod</code> or [[webadmin]]. <br />
<br />
If you unload modperl, all perl modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Writing new perl modules ==<br />
=== Basics ===<br />
<br />
Every perl module is file named like <code>modulename.pm</code> and is located in usual modules directories.<br />
The file must contain package with exactly the same name as the module itself.<br />
The module should be derived from <code>ZNC::Module</code>. <br />
<pre><br />
# perlexample.pm<br />
<br />
package perlexample;<br />
use base 'ZNC::Module';<br />
<br />
sub description {<br />
"Example perl module for ZNC"<br />
}<br />
<br />
sub OnChanMsg {<br />
my $self = shift;<br />
my ($nick, $chan, $msg) = @_;<br />
$self->PutModule("Hey, ".$nick->GetNick." said [$msg] on ".$chan->GetName);<br />
return $ZNC::CONTINUE;<br />
}<br />
<br />
1;<br />
</pre><br />
If you want to define several perl packages inside your module, you should name them as subpackages of your module package.<br />
See [[#Sockets|Sockets]] section for example. <br />
<br />
Description of the module is the return value from a <code>sub description</code>.<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in perl.<br />
The exception is callbacks which get vector<...> as last argument:<br />
<pre><br />
virtual void OnQuit(const CNick& Nick, const CString& sMessage, ''const vector<CChan*>& vChans'');<br />
</pre><br />
<pre><br />
sub OnQuit {<br />
my ($self, $nick, $message, ''@chans'') = @_;<br />
for (@chans) {<br />
$self->PutIRC("PRIVMSG ".$_->GetName." :Poor ".$nick->GetNick." :(");<br />
}<br />
}<br />
</pre><br />
<code>sub OnShutdown</code> is used as destructor (instead of perl's <code>DESTROY</code>).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded. <br />
<br />
If a callback returns undef, a reasonable default is substituted.<br />
Remember that if execution comes to end of sub, last evaluated value is returned!<br />
If a callback dies/croaks, the default value is assumed too, the behavior of what happens to arguments is undefined.<br />
When a module callback should return <code>CModule::EModRet</code>, you can use values as <code>$ZNC::CModule::CONTINUE</code> or just <code>$ZNC::CONTINUE</code>. <br />
<br />
Don't begin names of your member data fields with underscore (_) - some of them are used by modperl internally. <br />
<pre><br />
sub OnShutdown {<br />
my $self = shift;<br />
$self->{foo} = "foo"; # OK<br />
$self->{_bar} = "bar"; # Fail, probably will work but can randomly stop working.<br />
}<br />
</pre><br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for perl modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user perl modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
package perlusermod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::UserModule }<br />
<br />
For global modules use this:<br />
package perlglobalmod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::GlobalModule }<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
package perlusernetworkmod;<br />
use base 'ZNC::Module';<br />
sub module_types { $ZNC::CModInfo::UserModule, $ZNC::CModInfo::NetworkModule }<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod perlusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the functions like shown below:<br />
<br />
sub module_types { ... (see above section) }<br />
sub description { "This module does this and that" }<br />
sub wiki_page { "my_module" }<br />
sub has_args { 1 } # the default is 0<br />
sub args_help_text { "The arguments are foo and bar" }<br />
<br />
=== Strings ===<br />
All ZNC classes are accessible from perl with <code>ZNC::</code> prefix.<br />
The exception is <code>CString</code>. All uses of <code>CString</code> by value are transparently translated to/from perl string scalars. <br />
<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# perl<br />
my $str = "bar";<br />
ZNC::Foo($str); # OK<br />
my $num = 42;<br />
ZNC::Foo($num); # OK (only for ZNC >= 0.097)<br />
ZNC::Foo("$num"); # OK<br />
ZNC::Foo($num . ""); # OK<br />
ZNC::Foo(ZNC::String->new($num)); # OK, see below about ZNC::String<br />
<br />
If you need to ''call'' a function which gets <code>CString</code> by reference, and returns a value in it, there's a class named <code>ZNC::String</code>: <br />
<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# perl<br />
my $s = ZNC::String->new;<br />
ZNC::Foo($s);<br />
print $s->GetPerlStr; # prints 'bar' to stdout<br />
print $s; # The same, only for ZNC >= 1.7.0.<br />
<br />
As you see, to get normal string from <code>ZNC::String</code> there's a method <code>GetPerlStr</code>. Since ZNC 1.7.0 it's called automatically when string is needed.<br />
You can construct non-empty <code>ZNC::String</code> using an argument to <code>new</code>.<br />
This constructor can get string scalars, integer scalars, float scalars. <br />
<br />
When you implement a module hook which accepts <code>CString&</code>, no <code>ZNC::String</code> magic is needed, it just works: <br />
<pre><br />
sub OnChanMsg {<br />
my $self = shift;<br />
# @_ == (nick, channel, message)<br />
if ($_[0]->GetNick eq "Fish" || $_[2] eq "kwaa") {<br />
$_[2] = "moo!"<br />
}<br />
# the code above can be rewritten as follows:<br />
my ($nick, $channel, $message) = map {\$_} @_;<br />
if ($$nick->GetNick eq "Fish" || $$message eq "kwaa") {<br />
$$message = "moo!";<br />
}<br />
# alternatively, use \shift<br />
}<br />
</pre><br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
my $num_msg = $msg->As('CNumericMessage');<br />
</pre><br />
<br />
=== Module's NV ===<br />
There're some issues with using std iterators from perl, so class <code>CModule</code> got new methods: <code>GetNVKeys</code> which returns list of names of all NV values of the module, and <code>ExistsNV</code> which checks if specified variable exists. <br />
<pre><br />
sub OnModCommand {<br />
my $self = shift;<br />
my @nvkeys = $self->GetNVKeys;<br />
if ($self->ExistsNV("foo")) {<br />
$self->SetNV("bar", $self->GetNV("foo"));<br />
$self->DelNV("foo");<br />
}<br />
....<br />
}<br />
</pre><br />
Also there's another interface for accessing NVs - perl hash. (But for big number of values it's slow) <br />
<pre><br />
sub OnModCommand {<br />
my $self = shift;<br />
my $nv = $self->NV;<br />
while (my ($key, $value) = each %$nv) {<br />
...<br />
}<br />
my @nvkeys = keys %$nv;<br />
$nv->{foo} = "bar";<br />
$self->PutModule($nv->{foo});<br />
delete $nv->{foo};<br />
}<br />
</pre><br />
Of course, you can use $self->{foo} for storing temporary values, but NV data is stored on disk.<br />
<br />
=== IRCv3 capabilities ===<br />
<br />
Available since ZNC 1.9.<br />
<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>$self->AddServerDependentCapability()</code> accepts two code references:<br />
<br />
sub OnLoad {<br />
my $self = shift;<br />
$self->AddServerDependentCapability('testcap', sub {<br />
my ($ircnetwork, $state) = @_;<br />
$self->PutModule('Server changed support: ' . ($state ? 'true' : 'false'));<br />
}, sub {<br />
my ($client, $state) = @_;<br />
$self->PutModule('Client changed support: ' . ($state ? 'true' : 'false'));<br />
});<br />
return 1;<br />
}<br />
<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module. <br />
sub GetWebMenuTitle {<br />
"Perl test module"<br />
}<br />
==== CTemplate ====<br />
<br />
Instead of operator[] use set:<br />
<pre><br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
</pre><br />
<pre><br />
# perl equivalent<br />
my $tmpl = ...;<br />
$tmpl->set("name", "value");<br />
my $row = $tmpl->AddRow("SomeTable");<br />
$row->set("foo", "bar");<br />
</pre><br />
==== Subpages ====<br />
If you want to have subpages for the module, use helper function <code>ZNC::CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional named arguments: <br />
* title - text for displaying subpage name. By default it's the same as name. <br />
* params - reference to hash of parameters which will be used in URL linking to the subpage. <br />
* admin - set to true value if subpage should be accessible only by admins. <br />
<br />
There're 2 ways: using <code>AddSubPage</code>/<code>ClearSubPages</code> and overriding <code>GetSubPages</code>. <br />
<pre><br />
sub OnLoad {<br />
my $self = shift;<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page1'));<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page2', title=>'Page N2'));<br />
$self->AddSubPage(ZNC::CreateWebSubPage('page3', params=>{var1=>'value1', var2=>'value2'}, admin=>1);<br />
1<br />
}<br />
</pre><br />
The second way - to override <code>GetSubPages</code>. Perhaps(?) it may be better if list of subpages changes often in runtime. <br />
<br />
But don't return pointer to local variable! Perl destroys objects when reference count goes to zero. In these 2 examples additional reference to returned object is stored in <code>$self->{webpages}</code>. <br />
<pre><br />
sub OnLoad {<br />
my $self = shift;<br />
$self->{webpages} = ZNC::VWebSubPages->new;<br />
1<br />
}<br />
sub OnModCommand {<br />
my $self = shift;<br />
my $cmd = shift;<br />
$self->{webpages}->push(ZNC::CreateWebSubPage($cmd));<br />
}<br />
sub GetSubPages {<br />
my $self = shift;<br />
return $self->{webpages}<br />
}<br />
</pre><br />
<pre><br />
sub GetSubPages {<br />
my $self = shift;<br />
my $result = ZNC::VWebSubPages->new;<br />
$result->push(ZNC::CreateWebSubPage('foo'));<br />
$self->{webpages} = $result;<br />
return $result;<br />
}<br />
</pre><br />
<br />
=== Timers ===<br />
There're 2 APIs: first uses references to subs, second uses OOP packages. <br />
==== Ref API ====<br />
<br />
Use helper function <code>CreateTimer</code>.<br />
It gets following named arguments: <br />
* task ''(required)'' - Reference to a sub which will be called. The sub gets reference to your module as first argument, and ''context'' as named argument. <br />
* interval - Interval between calls, in seconds. Default is 10. <br />
* cycles - Number of times to run the sub. 0 means infinite. Default is 1. <br />
* description - Text description of the timer. Default doesn't matter. <br />
* label ''(overrideable since ZNC 1.9)'' - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default value is <code>perl-timer</code>.<br />
* context - Arbitrary value, which ''task'' will get as named argument context. <br />
<pre><br />
sub foo {<br />
my $self = shift;<br />
my %arg = @_;<br />
$self->PutStatus("foo ".$arg{context});<br />
}<br />
sub OnModCommand {<br />
my $self = shift;<br />
$self->CreateTimer(task=>\&foo, interval=>5, context=>'bar',<br />
description=>"Timer which puts 'foo bar' to status in 5 secs after user wrote something to the module");<br />
$self->CreateTimer(task=>sub {}, cycles=>0, interval=>1, description=>"Timer which every 1 second does nothing");<br />
}<br />
</pre><br />
==== OOP API ====<br />
''(available since ZNC 0.097) ''<br />
<br />
Use helper function <code>CreateTimer</code>. It gets following named arguments: <br />
* task ''(required)'' - name of your Timer class. It should be derived from <code>ZNC::Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>. <br />
* interval - Interval between calls, in seconds. Default is 10. <br />
* cycles - Number of times to run the sub. 0 means infinite. Default is 1. <br />
* description - Text description of the timer. Default doesn't matter. <br />
* label ''(overrideable since ZNC 1.9)'' - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default value is <code>perl-timer</code>.<br />
<pre><br />
# timerooptest.pm<br />
use strict;<br />
use warnings;<br />
<br />
package timerooptest::timer;<br />
use base 'ZNC::Timer';<br />
sub RunJob {<br />
my $self = shift;<br />
$self->GetModule->PutStatus('foo '.$self->{msg});<br />
}<br />
<br />
package timerooptest;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my $self = shift;<br />
my $timer = $self->CreateTimer(task=>'timerooptest::timer', interval=>4, cycles=>1,<br />
description=>'Says "foo bar" after 4 seconds');<br />
$timer->{msg} = 'bar';<br />
}<br />
</pre><br />
You can use methods of C++ class <code>CTimer</code> (like Stop) for your timer.<br />
<br />
=== Sockets ===<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special functions, which return true scalar if the feature is supported. <br />
<pre><br />
if (ZNC::HaveIPv6) {<br />
...<br />
}<br />
if (ZNC::HaveSSL) {<br />
...<br />
}<br />
if (ZNC::HaveCAres) {<br />
...<br />
}<br />
</pre><br />
All sockets are instances of special classes derived from <code>ZNC::Socket</code>.<br />
<code>ZNC::Socket</code> has all the same methods as <code>Csock</code>, except <code>Connect</code> and <code>Listen</code>.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to the associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of <code>Csock</code>, they are described later.<br />
<br />
To create socket, use module's method <code>CreateSocket</code>.<br />
First argument is the name of your socket class.<br />
The function creates socket and calls method <code>Init</code> of it with the rest of arguments.<br />
Reference to the new socket is returned. <br />
<br />
To connect socket, use method <code>Connect</code>.<br />
It gets 2 required arguments - hostname and port, and several optional named arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60. <br />
* ssl - Whether to use SSL for connection. <br />
* bindhost - Local interface to use for the connection. <br />
<br />
Returns true value if connection scheduled successfully.<br />
<pre><br />
# testmodule.pm<br />
<br />
package testmodule::connsock;<br />
use base 'ZNC::Socket';<br />
sub Init {<br />
my $self = shift;<br />
my $line = shift; # this and following arguments can be specified in CreateSocket<br />
$self->Connect('google.com', 80);<br />
$self->EnableReadLine;<br />
$self->Write("$line\r\n");<br />
}<br />
sub OnReadLine {<br />
my ($self, $line) = @_;<br />
$line =~ s/[\r\n]//g;<br />
$self->GetModule->PutStatus($line);<br />
}<br />
<br />
package testmodule;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my ($self, $cmd) = @_;<br />
my $sock = $self->CreateSocket('testmodule::connsock', "GET $cmd HTTP/1.0\r\n");<br />
}<br />
<br />
1;<br />
</pre><br />
<pre><br />
# testmodule2.pm<br />
<br />
package testmodule2::conn;<br />
use base 'ZNC::Socket';<br />
sub OnReadLine {<br />
my ($self, $line) = @_;<br />
$line =~ s/[\r\n]//g;<br />
$self->GetModule->PutStatus($line);<br />
}<br />
<br />
package testmodule2;<br />
use base 'ZNC::Module';<br />
sub OnModCommand {<br />
my ($self, $cmd) = @_;<br />
my $sock = $self->CreateSocket('testmodule2::connsock');<br />
$sock->Connect('google.com', 443, ssl=>1);<br />
$sock->EnableReadLine;<br />
$sock->Write("GET $cmd HTTP/1.0\r\n\r\n");<br />
}<br />
<br />
1;<br />
</pre><br />
<br />
To create listening socket, use method <code>Listen</code>.<br />
It gets following optional named arguments: <br />
* port - Port number to listen on. If not presented, random port is choosed. <br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces. <br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all. <br />
* ssl - Whether to use SSL for incoming connections. <br />
* maxconns - Maximum number of connections. Default is SOMAXCONN. <br />
* timeout - time in seconds, for timeout. <br />
<br />
Returns 0 on error and port number on success. <br />
<pre><br />
# testmodule3.pm<br />
<br />
package testmodule3::listensock;<br />
use base 'ZNC::Socket';<br />
sub OnAccepted {<br />
my ($self, $host, $port) = @_;<br />
$self->GetModule->CreateSocket('testmodule3::accepted', $host, $port);<br />
}<br />
<br />
package testmodule3::accepted;<br />
use base 'ZNC::Socket';<br />
sub Init {<br />
my ($self, $host, $port) = @_;<br />
$self->Write("Hello, $host:$port!\n");<br />
}<br />
sub OnReadData {<br />
my $self = shift;<br />
my ($data, $len) = @_;<br />
$self->Write($data, $len); # echo back everything<br />
}<br />
<br />
package testmodule3;<br />
use base 'ZNC::Module';<br />
sub OnLoad {<br />
my $self = shift;<br />
my $sock = $self->CreateSocket('testmodule3::listensock');<br />
my $port = $sock->Listen(ssl=>1, addrtype=>'ipv6');<br />
if ($port) {<br />
$_[1] = "Listening on all IPv6 interfaces on port $port using SSL";<br />
}<br />
1<br />
}<br />
<br />
1;<br />
</pre><br />
Sockets can override following callbacks: <br />
* <code>Init</code> - is called from <code>CreateSocket</code>, first argument is reference to socket, the rest is from arguments to <code>CreateSocket</code>. <br />
* <code>OnConnected</code><br />
* <code>OnDisconnected</code><br />
* <code>OnTimeout</code><br />
* <code>OnConnectionRefused</code><br />
* <code>OnReadData</code> - gets 2 arguments (of course, excluding reference to self): data and number of bytes. <br />
* <code>OnReadLine</code> - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket. <br />
* <code>OnAccepted</code> - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return undef if you don't need the connection, or reference to new socket, which will be used for this connection. <br />
* <code>OnShutdown</code> - ''(since 0.097)'' destructor of the socket. <br />
<br />
If callback <code>On*</code> dies/croaks, the socket is closed, but if you want to close socket, use method <code>Close</code> instead. If <code>Init</code> croaks, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>ZNC::CZNC::GetTag</code> is good. <br />
ZNC::CZNC::GetTag() # Returns, for example, 'ZNC 0.097 - http://znc.sourceforge.net'<br />
<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
Since ZNC 0.097, for getting ZNC version from Perl modules, you can use following functions: <br />
ZNC::GetVersion() # For example, number 0.097<br />
ZNC::GetVersionMajor() # 0<br />
ZNC::GetVersionMinor() # 97<br />
ZNC::GetVersionExtra() # build-specific string<br />
<br />
== Perl module Examples ==<br />
Here is a listing of useful perl modules<br />
* [https://github.com/DarthGandalf/znclinker ZNC-Linker bot]<br />
* [https://github.com/draggy/znc-perl-bitlbee-facebook-rename Facebook Bitlbee Rename]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modpython&diff=3118Modpython2024-02-11T09:36:47Z<p>DarthGandalf: /* IRCv3 capabilities */</p>
<hr />
<div>{{DISPLAYTITLE:modpython}}<br />
{{Core Module}}<br />
<br />
Modpython allows you to use modules written on python 3.<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-python, or cmake with -DWANT_PYTHON=ON.<br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed (Note: Must be => 3.0.0). If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
If for some reason you chose to compile python3 yourself, do it with --enable-shared option. If you use python from your distro (e.g. via apt-get, yum, etc), it is already compiled in the right way, no need to recompile anything.<br />
<br />
If python was compiled without this option, you may see errors like this: <code>/usr/local/lib/znc/modpython.so: undefined symbol: forkpty</code><br />
<br />
== Usage ==<br />
<br />
Loading and unloading of python3 modules is similar to C++ modules.<br />
For example, you can use <code>/znc loadmod</code> or [[webadmin]].<br />
<br />
If you unload modpython, all python modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Caveats ==<br />
* Python multithreading doesn't work properly. However you may try multiprocessing.<br />
* ZNC executes most of the operations (including Python modules) in single thread. It means you need to be careful not to block current thread, instead all your IRC connections may timeout. Webadmin will also stop working. Ideally you offload heavy operations to separate thread. Or actually to separate process, since multithreading doesn't work.<br />
<br />
== Writing new python3 modules ==<br />
=== Basics ===<br />
<br />
Every python module is file named like modulename.py (since ZNC 1.9 you can also use the package and name it modulename/__init__.py) and is located in usual modules directories (see [[Modules#Managing_Modules|here]] for details).<br />
The file '''must''' contain class with exactly the same name as the module itself.<br />
The class should be derived from <code>znc.Module</code>.<br />
<br />
# pythonexample.py<br />
<br />
import znc<br />
<br />
class pythonexample(znc.Module):<br />
description = "Example python3 module for ZNC"<br />
<br />
def OnChanMsg(self, nick, channel, message):<br />
self.PutModule("Hey, {0} said {1} on {2}".format(nick.GetNick(), message.s, channel.GetName()))<br />
return znc.CONTINUE<br />
<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in python.<br />
<br />
<code>def OnShutdown</code> is used as destructor (instead of python's __del__).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded.<br />
<br />
If a callback returns None or doesn't return anything instead of returning something (except for the <code>void</code> return type, of course), the behavior can be bizzare. Do not do this, even though sometimes it appears to work fine. In some future version this may be changed to check return types more strictly. The same goes for exceptions raised from the callback.<br />
<br />
When a module callback should return CModule::EModRet, you can use values such as <code>znc.CModule.CONTINUE</code> or just <code>znc.CONTINUE</code>.<br />
<br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for python modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user python modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
class pyusermod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule]<br />
<br />
For global modules use this:<br />
class pyglobalmod(znc.Module):<br />
module_types = [znc.CModInfo.GlobalModule]<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
class pyusernetworkmod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule, znc.CModInfo.NetworkModule]<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod pyusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the attributes like shown below:<br />
<br />
module_types = ... (see above section)<br />
description = "This module does this and that"<br />
wiki_page = "my_module"<br />
has_args = True (the default is False)<br />
args_help_text = "The arguments are foo and bar"<br />
<br />
=== Strings ===<br />
<br />
All ZNC classes are accessible from python with <code>znc.</code> prefix. The exception is CString.<br />
All uses of CString ''by value'' is transparently translated to/from python string objects.<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# python<br />
znc.Foo("bar")<br />
The same for case where you get CString by value:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(''const CString& sArgsi'', CString& sMessage);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if args == "bar":<br />
return True<br />
return False<br />
If you need to use CString ''by reference'', use class <code>znc.String</code> and its attribute <code>s</code>:<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# python<br />
x = znc.String()<br />
znc.Foo(x);<br />
print(x.s); # prints 'bar' to stdout<br />
The same if you get CString& as argument:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgsi, ''CString& sMessage'');<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
message.s = 'bar'<br />
return True<br />
<br />
'''Note''': don't try to use the string which you got in the overloaded method for calls to other methods<br />
<br />
# C++<br />
class CModule {<br />
virtual void OnFoo(CString& sMsg);<br />
void Bar(CString& sMsg); // appends "Bar" to sMsg<br />
}<br />
<br />
# python, wrong way<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
self.Bar(msg) # ZNC crashes here<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
s = znc.String()<br />
s.s = msg.s # so that old value is preserved<br />
self.Bar(s)<br />
msg.s = s.s # put result back to ''msg''<br />
<br />
So, you want to override a hook <code>void OnFoo(const CString& sBar)</code> and you actually don't want to write to <code>sBar</code>. So you probably will want to use the argument as python string. But, let's assume that in next ZNC version <code>OnFoo</code>'s signature will be changed to <code>void OnFoo(CString& sBar)</code>. This will break your module! To be on safe side, convert the argument to string with usual <code>str()</code> function. ('''Note:''' support for <code>str()</code> was added in ZNC 0.099) <br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgs, CString& sMessage);<br />
virtual EModRet OnRaw(CString& sLine);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if str(args).startswith('bar'):<br />
...<br />
def OnRaw(self, line):<br />
if str(line).startswith('bar'):<br />
...<br />
<br />
=== Booleans ===<br />
Moost booleans just work. If a callback gets <code>bool&</code> as a parameter, use this:<br />
<br />
// C++<br />
virtual EModRet OnModuleLoading(const CString& sModName, const CString& sArgs,<br />
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg);<br />
<br />
# python<br />
def OnModuleLoading(self, name, args, typ, success, retmsg):<br />
success.b = False # similar to string with its .s<br />
return znc.HALT<br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
num_msg = msg.As(znc.CNumericMessage)<br />
</pre><br />
<br />
=== Module's NV ===<br />
<br />
<code>module.nv</code> is a dict-like object, which can be used as normal dict, but stores it's data on disk. Both keys and values should be strings.<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
self.nv['bar'] = 'baz'<br />
if 'abcde' in self.nv:<br />
try:<br />
message.s = self.nv['qwerty']<br />
except KeyError:<br />
message.s = self.nv['abcde']<br />
for k, v = self.nv.items():<br />
...<br />
<br />
=== Objects ===<br />
<br />
SWIG distinguish between instances from ZNC and instances created in Python. All instances that are created during python time are garbage collected as soon they leave scope (e.g. at the end of the function or module). To move an instance to the ZNC scope, so it can be used after the lifetime of the function/module, set the special object property .thisown to 0.<br />
<br />
For example this is required if you add new user:<br />
<br />
new_user = znc.CUser(username)<br />
str_err = znc.String()<br />
if znc.CZNC.Get().AddUser(new_user, str_err):<br />
new_user.thisown = 0 # new_user won't be garbage collected at the end of the function anymore<br />
<br />
Similiar if you want to free an instance (like removing a listener), you should make sure that the memory gets garbage collected<br />
<br />
listener = ...<br />
if znc.CZNC.Get().DelListener(listener):<br />
listener.thisown = 1<br />
<br />
=== IRCv3 capabilities ===<br />
<br />
Available since ZNC 1.9.<br />
<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>self.AddServerDependentCapability()</code> accepts two callable objects:<br />
<br />
def OnLoad(self, args, ret):<br />
def server_change(ircnetwork, state):<br />
self.PutModule('Server changed support: ' + ('true' if state else 'false'))<br />
def client_change(client, state):<br />
self.PutModule('Client changed support: ' + ('true' if state else 'false'))<br />
self.AddServerDependentCapability('testcap', server_change, client_change)<br />
return True<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module.<br />
class test(znc.Module):<br />
def GetWebMenuTitle(self):<br />
return "Python test module"<br />
<br />
==== CTemplate ====<br />
<br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
<br />
# python equivalent (0.206 and below)<br />
tmpl = ...;<br />
tmpl.set("name", "value")<br />
row = tmpl.AddRow("SomeTable")<br />
row.set("foo", "bar")<br />
<br />
# python equivalent (since 0.207)<br />
tmpl = ...;<br />
tmpl["name"] = "value"<br />
row = tmpl.AddRow("SomeTable")<br />
row["foo"] = "bar"<br />
<br />
==== Subpages ====<br />
If you want to have subpages for the module, besides the main page, use helper function <code>znc.CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional arguments:<br />
* title - text for displaying subpage name. By default it's the same as name.<br />
* params - dict of parameters which will be used in URL linking to the subpage.<br />
* admin - set to True if subpage should be accessible only by admins.<br />
<br />
def OnLoad(self, args, message):<br />
self.AddSubPage(znc.CreateWebSubPage('page1'));<br />
self.AddSubPage(znc.CreateWebSubPage('page2', title='Page N2'))<br />
self.AddSubPage(znc.CreateWebSubPage('page3', params=dict(var1='value1', var2='value2'), admin=True))<br />
return True<br />
<br />
=== Timers ===<br />
Use helper function <code>CreateTimer</code>. It gets following arguments:<br />
* timer ''(required)'' - reference to your Timer class. It should be derived from <code>znc.Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>.<br />
* interval - Interval between calls, in seconds. Default is 10.<br />
* cycles - Number of times to run the <code>RunJob</code> function. 0 means infinite. Default is 1.<br />
* description - Text description of the timer. Default doesn't matter.<br />
* label - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default is <code>pytimer</code>.<br />
# timertest.py<br />
import znc<br />
<br />
class testtimer(znc.Timer):<br />
def RunJob(self):<br />
self.GetModule().PutStatus('foo {0}'.format(self.msg))<br />
<br />
class timertest(znc.Module):<br />
def OnModCommand(self, cmd):<br />
timer = self.CreateTimer(testtimer, interval=4, cycles=1, description='Says "foo bar" after 4 seconds', label='moo')<br />
timer.msg = 'bar'<br />
<br />
You can use methods of C++ class <code>CTimer</code> (like <code>Stop</code>) for your timer.<br />
<br />
=== Sockets ===<br />
<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special variables, which are True if the feature is supported.<br />
if znc.HaveIPv6:<br />
...<br />
if znc.HaveSSL:<br />
...<br />
if znc.HaveCAres:<br />
...<br />
All sockets are instances of special classes derived from <code>znc.Socket</code>.<br />
znc.Socket has all the same methods as Csock, except Connect, Listen and Write.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of Csock, they are described later.<br />
<br />
To create socket, use module's method CreateSocket. First argument is reference to your socket class. The function creates socket and calls method <code>Init</code> of it with the rest of arguments. Reference to the new socket is returned.<br />
<br />
To connect socket, use method <code>Connect</code>. It gets 2 required arguments - hostname and port, and several optional arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60.<br />
* ssl - Whether to use SSL for connection.<br />
* bindhost - Local interface to use for the connection.<br />
Returns true value if connection scheduled successfully.<br />
<br />
# networkconn.py<br />
import znc<br />
class connsock(znc.Socket):<br />
def Init(self, line): # line and other arguments, including named arguments can be specified in CreateSocket<br />
self.Connect('google.com', 80)<br />
self.EnableReadLine()<br />
self.Write("{0}\r\n".format(line))<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line) # this puts also \n and \r to status, which is not very good, but this is just an example, so...<br />
<br />
class networkconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(connsock, "GET {0} HTTP/1.0\r\n".format(cmd))<br />
<br />
# socketconn.py<br />
import znc<br />
class conn(znc.Socket):<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line)<br />
<br />
class socketconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(conn)<br />
sock.Connect('google.com', 443, ssl=True)<br />
sock.EnableReadLine()<br />
sock.Write("GET {0} HTTP/1.0\r\n\r\n".format(cmd))<br />
<br />
To create listening socket, use method <code>Listen</code>. It gets following optional named arguments:<br />
* port - Port number to listen on. If not presented, random port is choosed.<br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces.<br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all.<br />
* ssl - Whether to use SSL for incoming connections.<br />
* maxconns - Maximum number of connections. Default is SOMAXCONN.<br />
* timeout - time in seconds, for timeout.<br />
Returns 0 on error and port number on success.<br />
# listmodule.py<br />
import znc<br />
<br />
class accepted(znc.Socket):<br />
def Init(self, host, port):<br />
self.Write("Hello, {0}:{1}!\n".format(host, port))<br />
def OnReadData(self, data):<br />
self.WriteBytes(data) # echo back everything<br />
<br />
class listensock(znc.Socket):<br />
def OnAccepted(self, host, port):<br />
return self.GetModule().CreateSocket(accepted, host, port)<br />
<br />
class listmodule(znc.Module):<br />
def OnLoad(self, args, message):<br />
sock = self.CreateSocket(listensock)<br />
port = sock.Listen(ssl=True, addrtype='ipv6');<br />
if port > 0:<br />
message.s = "Listening on all IPv6 interfaces on port {0} using SSL".format(port)<br />
return True<br />
<br />
Use <code>Write</code> to write strings, and <code>WriteBytes</code> to write binary data.<br />
<br />
Sockets can override following callbacks:<br />
* Init - is called from CreateSocket, first argument is reference to socket, the rest is from arguments to CreateSocket.<br />
* OnConnected<br />
* OnDisconnected<br />
* OnTimeout<br />
* OnConnectionRefused<br />
* OnReadData - gets bytes as second argument<br />
* OnReadLine - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket.<br />
* OnAccepted - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return None if you don't need the connection, or reference to new socket, which will be used for this connection.<br />
* OnShutdown - destructor of the socket.<br />
<br />
If callback On* raises an exception, the socket is closed, but if you want to close socket, use method <code>Close</code> instead.<br />
If Init raises an exception, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>znc.CZNC.GetTag()</code> is good.<br />
znc.CZNC.GetTag() # Returns, for example, 'ZNC 0.097 - http:/<nowiki></nowiki>/znc.sourceforge.net'<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
For getting ZNC version, you can use read following variables:<br />
znc.Version # For example, number 0.097<br />
znc.VersionMajor # 0<br />
znc.VersionMinor # 97<br />
znc.VersionExtra # build-specific string<br />
<br />
<br />
[[Category:Modules]]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modpython&diff=3117Modpython2024-02-11T09:36:29Z<p>DarthGandalf: </p>
<hr />
<div>{{DISPLAYTITLE:modpython}}<br />
{{Core Module}}<br />
<br />
Modpython allows you to use modules written on python 3.<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-python, or cmake with -DWANT_PYTHON=ON.<br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed (Note: Must be => 3.0.0). If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
If for some reason you chose to compile python3 yourself, do it with --enable-shared option. If you use python from your distro (e.g. via apt-get, yum, etc), it is already compiled in the right way, no need to recompile anything.<br />
<br />
If python was compiled without this option, you may see errors like this: <code>/usr/local/lib/znc/modpython.so: undefined symbol: forkpty</code><br />
<br />
== Usage ==<br />
<br />
Loading and unloading of python3 modules is similar to C++ modules.<br />
For example, you can use <code>/znc loadmod</code> or [[webadmin]].<br />
<br />
If you unload modpython, all python modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Caveats ==<br />
* Python multithreading doesn't work properly. However you may try multiprocessing.<br />
* ZNC executes most of the operations (including Python modules) in single thread. It means you need to be careful not to block current thread, instead all your IRC connections may timeout. Webadmin will also stop working. Ideally you offload heavy operations to separate thread. Or actually to separate process, since multithreading doesn't work.<br />
<br />
== Writing new python3 modules ==<br />
=== Basics ===<br />
<br />
Every python module is file named like modulename.py (since ZNC 1.9 you can also use the package and name it modulename/__init__.py) and is located in usual modules directories (see [[Modules#Managing_Modules|here]] for details).<br />
The file '''must''' contain class with exactly the same name as the module itself.<br />
The class should be derived from <code>znc.Module</code>.<br />
<br />
# pythonexample.py<br />
<br />
import znc<br />
<br />
class pythonexample(znc.Module):<br />
description = "Example python3 module for ZNC"<br />
<br />
def OnChanMsg(self, nick, channel, message):<br />
self.PutModule("Hey, {0} said {1} on {2}".format(nick.GetNick(), message.s, channel.GetName()))<br />
return znc.CONTINUE<br />
<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in python.<br />
<br />
<code>def OnShutdown</code> is used as destructor (instead of python's __del__).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded.<br />
<br />
If a callback returns None or doesn't return anything instead of returning something (except for the <code>void</code> return type, of course), the behavior can be bizzare. Do not do this, even though sometimes it appears to work fine. In some future version this may be changed to check return types more strictly. The same goes for exceptions raised from the callback.<br />
<br />
When a module callback should return CModule::EModRet, you can use values such as <code>znc.CModule.CONTINUE</code> or just <code>znc.CONTINUE</code>.<br />
<br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for python modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user python modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
class pyusermod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule]<br />
<br />
For global modules use this:<br />
class pyglobalmod(znc.Module):<br />
module_types = [znc.CModInfo.GlobalModule]<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
class pyusernetworkmod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule, znc.CModInfo.NetworkModule]<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod pyusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the attributes like shown below:<br />
<br />
module_types = ... (see above section)<br />
description = "This module does this and that"<br />
wiki_page = "my_module"<br />
has_args = True (the default is False)<br />
args_help_text = "The arguments are foo and bar"<br />
<br />
=== Strings ===<br />
<br />
All ZNC classes are accessible from python with <code>znc.</code> prefix. The exception is CString.<br />
All uses of CString ''by value'' is transparently translated to/from python string objects.<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# python<br />
znc.Foo("bar")<br />
The same for case where you get CString by value:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(''const CString& sArgsi'', CString& sMessage);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if args == "bar":<br />
return True<br />
return False<br />
If you need to use CString ''by reference'', use class <code>znc.String</code> and its attribute <code>s</code>:<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# python<br />
x = znc.String()<br />
znc.Foo(x);<br />
print(x.s); # prints 'bar' to stdout<br />
The same if you get CString& as argument:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgsi, ''CString& sMessage'');<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
message.s = 'bar'<br />
return True<br />
<br />
'''Note''': don't try to use the string which you got in the overloaded method for calls to other methods<br />
<br />
# C++<br />
class CModule {<br />
virtual void OnFoo(CString& sMsg);<br />
void Bar(CString& sMsg); // appends "Bar" to sMsg<br />
}<br />
<br />
# python, wrong way<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
self.Bar(msg) # ZNC crashes here<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
s = znc.String()<br />
s.s = msg.s # so that old value is preserved<br />
self.Bar(s)<br />
msg.s = s.s # put result back to ''msg''<br />
<br />
So, you want to override a hook <code>void OnFoo(const CString& sBar)</code> and you actually don't want to write to <code>sBar</code>. So you probably will want to use the argument as python string. But, let's assume that in next ZNC version <code>OnFoo</code>'s signature will be changed to <code>void OnFoo(CString& sBar)</code>. This will break your module! To be on safe side, convert the argument to string with usual <code>str()</code> function. ('''Note:''' support for <code>str()</code> was added in ZNC 0.099) <br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgs, CString& sMessage);<br />
virtual EModRet OnRaw(CString& sLine);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if str(args).startswith('bar'):<br />
...<br />
def OnRaw(self, line):<br />
if str(line).startswith('bar'):<br />
...<br />
<br />
=== Booleans ===<br />
Moost booleans just work. If a callback gets <code>bool&</code> as a parameter, use this:<br />
<br />
// C++<br />
virtual EModRet OnModuleLoading(const CString& sModName, const CString& sArgs,<br />
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg);<br />
<br />
# python<br />
def OnModuleLoading(self, name, args, typ, success, retmsg):<br />
success.b = False # similar to string with its .s<br />
return znc.HALT<br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
num_msg = msg.As(znc.CNumericMessage)<br />
</pre><br />
<br />
=== Module's NV ===<br />
<br />
<code>module.nv</code> is a dict-like object, which can be used as normal dict, but stores it's data on disk. Both keys and values should be strings.<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
self.nv['bar'] = 'baz'<br />
if 'abcde' in self.nv:<br />
try:<br />
message.s = self.nv['qwerty']<br />
except KeyError:<br />
message.s = self.nv['abcde']<br />
for k, v = self.nv.items():<br />
...<br />
<br />
=== Objects ===<br />
<br />
SWIG distinguish between instances from ZNC and instances created in Python. All instances that are created during python time are garbage collected as soon they leave scope (e.g. at the end of the function or module). To move an instance to the ZNC scope, so it can be used after the lifetime of the function/module, set the special object property .thisown to 0.<br />
<br />
For example this is required if you add new user:<br />
<br />
new_user = znc.CUser(username)<br />
str_err = znc.String()<br />
if znc.CZNC.Get().AddUser(new_user, str_err):<br />
new_user.thisown = 0 # new_user won't be garbage collected at the end of the function anymore<br />
<br />
Similiar if you want to free an instance (like removing a listener), you should make sure that the memory gets garbage collected<br />
<br />
listener = ...<br />
if znc.CZNC.Get().DelListener(listener):<br />
listener.thisown = 1<br />
<br />
=== IRCv3 capabilities ===<br />
While in C++ you'd need to inherit from <code>CCapability</code>, here <code>self.AddServerDependentCapability()</code> accepts two callable objects:<br />
<br />
def OnLoad(self, args, ret):<br />
def server_change(ircnetwork, state):<br />
self.PutModule('Server changed support: ' + ('true' if state else 'false'))<br />
def client_change(client, state):<br />
self.PutModule('Client changed support: ' + ('true' if state else 'false'))<br />
self.AddServerDependentCapability('testcap', server_change, client_change)<br />
return True<br />
<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module.<br />
class test(znc.Module):<br />
def GetWebMenuTitle(self):<br />
return "Python test module"<br />
<br />
==== CTemplate ====<br />
<br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
<br />
# python equivalent (0.206 and below)<br />
tmpl = ...;<br />
tmpl.set("name", "value")<br />
row = tmpl.AddRow("SomeTable")<br />
row.set("foo", "bar")<br />
<br />
# python equivalent (since 0.207)<br />
tmpl = ...;<br />
tmpl["name"] = "value"<br />
row = tmpl.AddRow("SomeTable")<br />
row["foo"] = "bar"<br />
<br />
==== Subpages ====<br />
If you want to have subpages for the module, besides the main page, use helper function <code>znc.CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional arguments:<br />
* title - text for displaying subpage name. By default it's the same as name.<br />
* params - dict of parameters which will be used in URL linking to the subpage.<br />
* admin - set to True if subpage should be accessible only by admins.<br />
<br />
def OnLoad(self, args, message):<br />
self.AddSubPage(znc.CreateWebSubPage('page1'));<br />
self.AddSubPage(znc.CreateWebSubPage('page2', title='Page N2'))<br />
self.AddSubPage(znc.CreateWebSubPage('page3', params=dict(var1='value1', var2='value2'), admin=True))<br />
return True<br />
<br />
=== Timers ===<br />
Use helper function <code>CreateTimer</code>. It gets following arguments:<br />
* timer ''(required)'' - reference to your Timer class. It should be derived from <code>znc.Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>.<br />
* interval - Interval between calls, in seconds. Default is 10.<br />
* cycles - Number of times to run the <code>RunJob</code> function. 0 means infinite. Default is 1.<br />
* description - Text description of the timer. Default doesn't matter.<br />
* label - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default is <code>pytimer</code>.<br />
# timertest.py<br />
import znc<br />
<br />
class testtimer(znc.Timer):<br />
def RunJob(self):<br />
self.GetModule().PutStatus('foo {0}'.format(self.msg))<br />
<br />
class timertest(znc.Module):<br />
def OnModCommand(self, cmd):<br />
timer = self.CreateTimer(testtimer, interval=4, cycles=1, description='Says "foo bar" after 4 seconds', label='moo')<br />
timer.msg = 'bar'<br />
<br />
You can use methods of C++ class <code>CTimer</code> (like <code>Stop</code>) for your timer.<br />
<br />
=== Sockets ===<br />
<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special variables, which are True if the feature is supported.<br />
if znc.HaveIPv6:<br />
...<br />
if znc.HaveSSL:<br />
...<br />
if znc.HaveCAres:<br />
...<br />
All sockets are instances of special classes derived from <code>znc.Socket</code>.<br />
znc.Socket has all the same methods as Csock, except Connect, Listen and Write.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of Csock, they are described later.<br />
<br />
To create socket, use module's method CreateSocket. First argument is reference to your socket class. The function creates socket and calls method <code>Init</code> of it with the rest of arguments. Reference to the new socket is returned.<br />
<br />
To connect socket, use method <code>Connect</code>. It gets 2 required arguments - hostname and port, and several optional arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60.<br />
* ssl - Whether to use SSL for connection.<br />
* bindhost - Local interface to use for the connection.<br />
Returns true value if connection scheduled successfully.<br />
<br />
# networkconn.py<br />
import znc<br />
class connsock(znc.Socket):<br />
def Init(self, line): # line and other arguments, including named arguments can be specified in CreateSocket<br />
self.Connect('google.com', 80)<br />
self.EnableReadLine()<br />
self.Write("{0}\r\n".format(line))<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line) # this puts also \n and \r to status, which is not very good, but this is just an example, so...<br />
<br />
class networkconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(connsock, "GET {0} HTTP/1.0\r\n".format(cmd))<br />
<br />
# socketconn.py<br />
import znc<br />
class conn(znc.Socket):<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line)<br />
<br />
class socketconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(conn)<br />
sock.Connect('google.com', 443, ssl=True)<br />
sock.EnableReadLine()<br />
sock.Write("GET {0} HTTP/1.0\r\n\r\n".format(cmd))<br />
<br />
To create listening socket, use method <code>Listen</code>. It gets following optional named arguments:<br />
* port - Port number to listen on. If not presented, random port is choosed.<br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces.<br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all.<br />
* ssl - Whether to use SSL for incoming connections.<br />
* maxconns - Maximum number of connections. Default is SOMAXCONN.<br />
* timeout - time in seconds, for timeout.<br />
Returns 0 on error and port number on success.<br />
# listmodule.py<br />
import znc<br />
<br />
class accepted(znc.Socket):<br />
def Init(self, host, port):<br />
self.Write("Hello, {0}:{1}!\n".format(host, port))<br />
def OnReadData(self, data):<br />
self.WriteBytes(data) # echo back everything<br />
<br />
class listensock(znc.Socket):<br />
def OnAccepted(self, host, port):<br />
return self.GetModule().CreateSocket(accepted, host, port)<br />
<br />
class listmodule(znc.Module):<br />
def OnLoad(self, args, message):<br />
sock = self.CreateSocket(listensock)<br />
port = sock.Listen(ssl=True, addrtype='ipv6');<br />
if port > 0:<br />
message.s = "Listening on all IPv6 interfaces on port {0} using SSL".format(port)<br />
return True<br />
<br />
Use <code>Write</code> to write strings, and <code>WriteBytes</code> to write binary data.<br />
<br />
Sockets can override following callbacks:<br />
* Init - is called from CreateSocket, first argument is reference to socket, the rest is from arguments to CreateSocket.<br />
* OnConnected<br />
* OnDisconnected<br />
* OnTimeout<br />
* OnConnectionRefused<br />
* OnReadData - gets bytes as second argument<br />
* OnReadLine - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket.<br />
* OnAccepted - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return None if you don't need the connection, or reference to new socket, which will be used for this connection.<br />
* OnShutdown - destructor of the socket.<br />
<br />
If callback On* raises an exception, the socket is closed, but if you want to close socket, use method <code>Close</code> instead.<br />
If Init raises an exception, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>znc.CZNC.GetTag()</code> is good.<br />
znc.CZNC.GetTag() # Returns, for example, 'ZNC 0.097 - http:/<nowiki></nowiki>/znc.sourceforge.net'<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
For getting ZNC version, you can use read following variables:<br />
znc.Version # For example, number 0.097<br />
znc.VersionMajor # 0<br />
znc.VersionMinor # 97<br />
znc.VersionExtra # build-specific string<br />
<br />
<br />
[[Category:Modules]]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Modpython&diff=3116Modpython2024-02-11T09:28:22Z<p>DarthGandalf: /* Basics */</p>
<hr />
<div>{{DISPLAYTITLE:modpython}}<br />
{{Core Module}}<br />
<br />
Modpython allows you to use modules written on python 3.<br />
<br />
== Compiling ==<br />
First, you need to use ./configure with option --enable-python, or cmake with -DWANT_PYTHON=ON.<br />
<br />
If you're building from [[git]], you need to have [http://www.swig.org/ SWIG] installed (Note: Must be => 3.0.0). If you're building from tarball (nightly or release), SWIG is not required.<br />
<br />
If for some reason you chose to compile python3 yourself, do it with --enable-shared option. If you use python from your distro (e.g. via apt-get, yum, etc), it is already compiled in the right way, no need to recompile anything.<br />
<br />
If python was compiled without this option, you may see errors like this: <code>/usr/local/lib/znc/modpython.so: undefined symbol: forkpty</code><br />
<br />
== Usage ==<br />
<br />
Loading and unloading of python3 modules is similar to C++ modules.<br />
For example, you can use <code>/znc loadmod</code> or [[webadmin]].<br />
<br />
If you unload modpython, all python modules are automatically unloaded too.<br />
<br />
{{Module arguments|type=global}}<br />
<br />
== Caveats ==<br />
* Python multithreading doesn't work properly. However you may try multiprocessing.<br />
* ZNC executes most of the operations (including Python modules) in single thread. It means you need to be careful not to block current thread, instead all your IRC connections may timeout. Webadmin will also stop working. Ideally you offload heavy operations to separate thread. Or actually to separate process, since multithreading doesn't work.<br />
<br />
== Writing new python3 modules ==<br />
=== Basics ===<br />
<br />
Every python module is file named like modulename.py (since ZNC 1.9 you can also use the package and name it modulename/__init__.py) and is located in usual modules directories (see [[Modules#Managing_Modules|here]] for details).<br />
The file '''must''' contain class with exactly the same name as the module itself.<br />
The class should be derived from <code>znc.Module</code>.<br />
<br />
# pythonexample.py<br />
<br />
import znc<br />
<br />
class pythonexample(znc.Module):<br />
description = "Example python3 module for ZNC"<br />
<br />
def OnChanMsg(self, nick, channel, message):<br />
self.PutModule("Hey, {0} said {1} on {2}".format(nick.GetNick(), message.s, channel.GetName()))<br />
return znc.CONTINUE<br />
<br />
All callbacks have the same name as in C++, and have the same arguments, but with reference to self before first argument, as usually in python.<br />
<br />
<code>def OnShutdown</code> is used as destructor (instead of python's __del__).<br />
<code>OnShutdown</code> is called when the module is going to be unloaded.<br />
<br />
If a callback returns None or doesn't return anything instead of returning something (except for the <code>void</code> return type, of course), the behavior can be bizzare. Do not do this, even though sometimes it appears to work fine. In some future version this may be changed to check return types more strictly. The same goes for exceptions raised from the callback.<br />
<br />
When a module callback should return CModule::EModRet, you can use values such as <code>znc.CModule.CONTINUE</code> or just <code>znc.CONTINUE</code>.<br />
<br />
ZNC C++ API can be found [http://docs.znc.in/ here].<br />
Most of it should just work for python modules.<br />
The following text describes mostly features, differences and caveats.<br />
<br />
=== Module types ===<br />
Before ZNC 0.207 only user python modules are supported.<br />
Since ZNC 0.207 network, user and global modules are supported.<br />
By default every module is network-only.<br />
<br />
If you want to make your module accessible only at user level, use this:<br />
class pyusermod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule]<br />
<br />
For global modules use this:<br />
class pyglobalmod(znc.Module):<br />
module_types = [znc.CModInfo.GlobalModule]<br />
<br />
If you want to make your module to be loadable as both user module and network module, use this:<br />
class pyusernetworkmod(znc.Module):<br />
module_types = [znc.CModInfo.UserModule, znc.CModInfo.NetworkModule]<br />
The first element of the list is the default module type. It's used when no type is specified. So <code>/znc loadmod pyusernetworkmod</code> will load it as user module.<br />
<br />
=== Module metadata ===<br />
<br />
Several settings can be configured, using the attributes like shown below:<br />
<br />
module_types = ... (see above section)<br />
description = "This module does this and that"<br />
wiki_page = "my_module"<br />
has_args = True (the default is False)<br />
args_help_text = "The arguments are foo and bar"<br />
<br />
=== Strings ===<br />
<br />
All ZNC classes are accessible from python with <code>znc.</code> prefix. The exception is CString.<br />
All uses of CString ''by value'' is transparently translated to/from python string objects.<br />
// C++<br />
void Foo(const CString& s);<br />
<br />
# python<br />
znc.Foo("bar")<br />
The same for case where you get CString by value:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(''const CString& sArgsi'', CString& sMessage);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if args == "bar":<br />
return True<br />
return False<br />
If you need to use CString ''by reference'', use class <code>znc.String</code> and its attribute <code>s</code>:<br />
// C++<br />
void Foo(CString& s) {<br />
s = "bar";<br />
}<br />
<br />
# python<br />
x = znc.String()<br />
znc.Foo(x);<br />
print(x.s); # prints 'bar' to stdout<br />
The same if you get CString& as argument:<br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgsi, ''CString& sMessage'');<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
message.s = 'bar'<br />
return True<br />
<br />
'''Note''': don't try to use the string which you got in the overloaded method for calls to other methods<br />
<br />
# C++<br />
class CModule {<br />
virtual void OnFoo(CString& sMsg);<br />
void Bar(CString& sMsg); // appends "Bar" to sMsg<br />
}<br />
<br />
# python, wrong way<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
self.Bar(msg) # ZNC crashes here<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnFoo(self, msg):<br />
s = znc.String()<br />
s.s = msg.s # so that old value is preserved<br />
self.Bar(s)<br />
msg.s = s.s # put result back to ''msg''<br />
<br />
So, you want to override a hook <code>void OnFoo(const CString& sBar)</code> and you actually don't want to write to <code>sBar</code>. So you probably will want to use the argument as python string. But, let's assume that in next ZNC version <code>OnFoo</code>'s signature will be changed to <code>void OnFoo(CString& sBar)</code>. This will break your module! To be on safe side, convert the argument to string with usual <code>str()</code> function. ('''Note:''' support for <code>str()</code> was added in ZNC 0.099) <br />
// C++<br />
class CModule {<br />
...<br />
virtual bool OnLoad(const CString& sArgs, CString& sMessage);<br />
virtual EModRet OnRaw(CString& sLine);<br />
};<br />
<br />
# python<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
if str(args).startswith('bar'):<br />
...<br />
def OnRaw(self, line):<br />
if str(line).startswith('bar'):<br />
...<br />
<br />
=== Booleans ===<br />
Moost booleans just work. If a callback gets <code>bool&</code> as a parameter, use this:<br />
<br />
// C++<br />
virtual EModRet OnModuleLoading(const CString& sModName, const CString& sArgs,<br />
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg);<br />
<br />
# python<br />
def OnModuleLoading(self, name, args, typ, success, retmsg):<br />
success.b = False # similar to string with its .s<br />
return znc.HALT<br />
<br />
=== Message types ===<br />
Since ZNC 1.7.0.<br />
<br />
To convert between various subclasses of <code>CMessage</code>, use this:<br />
<pre><br />
num_msg = msg.As(znc.CNumericMessage)<br />
</pre><br />
<br />
=== Module's NV ===<br />
<br />
<code>module.nv</code> is a dict-like object, which can be used as normal dict, but stores it's data on disk. Both keys and values should be strings.<br />
class foo(znc.Module):<br />
def OnLoad(self, args, message):<br />
self.nv['bar'] = 'baz'<br />
if 'abcde' in self.nv:<br />
try:<br />
message.s = self.nv['qwerty']<br />
except KeyError:<br />
message.s = self.nv['abcde']<br />
for k, v = self.nv.items():<br />
...<br />
<br />
=== Objects ===<br />
<br />
SWIG distinguish between instances from ZNC and instances created in Python. All instances that are created during python time are garbage collected as soon they leave scope (e.g. at the end of the function or module). To move an instance to the ZNC scope, so it can be used after the lifetime of the function/module, set the special object property .thisown to 0.<br />
<br />
For example this is required if you add new user:<br />
<br />
new_user = znc.CUser(username)<br />
str_err = znc.String()<br />
if znc.CZNC.Get().AddUser(new_user, str_err):<br />
new_user.thisown = 0 # new_user won't be garbage collected at the end of the function anymore<br />
<br />
Similiar if you want to free an instance (like removing a listener), you should make sure that the memory gets garbage collected<br />
<br />
listener = ...<br />
if znc.CZNC.Get().DelListener(listener):<br />
listener.thisown = 1<br />
<br />
<br />
=== Web ===<br />
<br />
See [[WebMods]] for an overview.<br />
<br />
To show your module's page or subpages in the menu, need to define <code>GetWebMenuTitle</code> which should return visual name for the module.<br />
class test(znc.Module):<br />
def GetWebMenuTitle(self):<br />
return "Python test module"<br />
<br />
==== CTemplate ====<br />
<br />
// C++<br />
CTemplate& tmpl = ...;<br />
tmpl["name"] = "value";<br />
CTemplate& row = tmpl.AddRow("SomeTable");<br />
row["foo"] = "bar";<br />
<br />
# python equivalent (0.206 and below)<br />
tmpl = ...;<br />
tmpl.set("name", "value")<br />
row = tmpl.AddRow("SomeTable")<br />
row.set("foo", "bar")<br />
<br />
# python equivalent (since 0.207)<br />
tmpl = ...;<br />
tmpl["name"] = "value"<br />
row = tmpl.AddRow("SomeTable")<br />
row["foo"] = "bar"<br />
<br />
==== Subpages ====<br />
If you want to have subpages for the module, besides the main page, use helper function <code>znc.CreateWebSubPage</code>.<br />
It accepts one required argument - name of the subpage, and several optional arguments:<br />
* title - text for displaying subpage name. By default it's the same as name.<br />
* params - dict of parameters which will be used in URL linking to the subpage.<br />
* admin - set to True if subpage should be accessible only by admins.<br />
<br />
def OnLoad(self, args, message):<br />
self.AddSubPage(znc.CreateWebSubPage('page1'));<br />
self.AddSubPage(znc.CreateWebSubPage('page2', title='Page N2'))<br />
self.AddSubPage(znc.CreateWebSubPage('page3', params=dict(var1='value1', var2='value2'), admin=True))<br />
return True<br />
<br />
=== Timers ===<br />
Use helper function <code>CreateTimer</code>. It gets following arguments:<br />
* timer ''(required)'' - reference to your Timer class. It should be derived from <code>znc.Timer</code>. You can override 2 methods: <code>RunJob</code> and <code>OnShutdown</code>.<br />
* interval - Interval between calls, in seconds. Default is 10.<br />
* cycles - Number of times to run the <code>RunJob</code> function. 0 means infinite. Default is 1.<br />
* description - Text description of the timer. Default doesn't matter.<br />
* label - String identifying the timer. If the module already has an active timer with the same label, the new one will not be created. Default is <code>pytimer</code>.<br />
# timertest.py<br />
import znc<br />
<br />
class testtimer(znc.Timer):<br />
def RunJob(self):<br />
self.GetModule().PutStatus('foo {0}'.format(self.msg))<br />
<br />
class timertest(znc.Module):<br />
def OnModCommand(self, cmd):<br />
timer = self.CreateTimer(testtimer, interval=4, cycles=1, description='Says "foo bar" after 4 seconds', label='moo')<br />
timer.msg = 'bar'<br />
<br />
You can use methods of C++ class <code>CTimer</code> (like <code>Stop</code>) for your timer.<br />
<br />
=== Sockets ===<br />
<br />
If module needs to know whether ZNC was compiled with IPv6, SSL and c-ares support, you can use special variables, which are True if the feature is supported.<br />
if znc.HaveIPv6:<br />
...<br />
if znc.HaveSSL:<br />
...<br />
if znc.HaveCAres:<br />
...<br />
All sockets are instances of special classes derived from <code>znc.Socket</code>.<br />
znc.Socket has all the same methods as Csock, except Connect, Listen and Write.<br />
Csock's reference can be found [http://csocket.net/docs/annotated.html here].<br />
To get reference to associated module, use <code>GetModule</code>.<br />
Callbacks have different names from ones of Csock, they are described later.<br />
<br />
To create socket, use module's method CreateSocket. First argument is reference to your socket class. The function creates socket and calls method <code>Init</code> of it with the rest of arguments. Reference to the new socket is returned.<br />
<br />
To connect socket, use method <code>Connect</code>. It gets 2 required arguments - hostname and port, and several optional arguments:<br />
* timeout - Time in seconds to wait for connection. Default is 60.<br />
* ssl - Whether to use SSL for connection.<br />
* bindhost - Local interface to use for the connection.<br />
Returns true value if connection scheduled successfully.<br />
<br />
# networkconn.py<br />
import znc<br />
class connsock(znc.Socket):<br />
def Init(self, line): # line and other arguments, including named arguments can be specified in CreateSocket<br />
self.Connect('google.com', 80)<br />
self.EnableReadLine()<br />
self.Write("{0}\r\n".format(line))<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line) # this puts also \n and \r to status, which is not very good, but this is just an example, so...<br />
<br />
class networkconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(connsock, "GET {0} HTTP/1.0\r\n".format(cmd))<br />
<br />
# socketconn.py<br />
import znc<br />
class conn(znc.Socket):<br />
def OnReadLine(self, line):<br />
self.GetModule().PutStatus(line)<br />
<br />
class socketconn(znc.Module):<br />
def OnModCommand(self, cmd):<br />
sock = self.CreateSocket(conn)<br />
sock.Connect('google.com', 443, ssl=True)<br />
sock.EnableReadLine()<br />
sock.Write("GET {0} HTTP/1.0\r\n\r\n".format(cmd))<br />
<br />
To create listening socket, use method <code>Listen</code>. It gets following optional named arguments:<br />
* port - Port number to listen on. If not presented, random port is choosed.<br />
* bindhost - Interface to listen on. If not presented, socket will listen on all interfaces.<br />
* addrtype - Chooses protocol family. Possible values are 'all', 'ipv4' and 'ipv6'. Default is all.<br />
* ssl - Whether to use SSL for incoming connections.<br />
* maxconns - Maximum number of connections. Default is SOMAXCONN.<br />
* timeout - time in seconds, for timeout.<br />
Returns 0 on error and port number on success.<br />
# listmodule.py<br />
import znc<br />
<br />
class accepted(znc.Socket):<br />
def Init(self, host, port):<br />
self.Write("Hello, {0}:{1}!\n".format(host, port))<br />
def OnReadData(self, data):<br />
self.WriteBytes(data) # echo back everything<br />
<br />
class listensock(znc.Socket):<br />
def OnAccepted(self, host, port):<br />
return self.GetModule().CreateSocket(accepted, host, port)<br />
<br />
class listmodule(znc.Module):<br />
def OnLoad(self, args, message):<br />
sock = self.CreateSocket(listensock)<br />
port = sock.Listen(ssl=True, addrtype='ipv6');<br />
if port > 0:<br />
message.s = "Listening on all IPv6 interfaces on port {0} using SSL".format(port)<br />
return True<br />
<br />
Use <code>Write</code> to write strings, and <code>WriteBytes</code> to write binary data.<br />
<br />
Sockets can override following callbacks:<br />
* Init - is called from CreateSocket, first argument is reference to socket, the rest is from arguments to CreateSocket.<br />
* OnConnected<br />
* OnDisconnected<br />
* OnTimeout<br />
* OnConnectionRefused<br />
* OnReadData - gets bytes as second argument<br />
* OnReadLine - is called for every new line from socket. The line, including ending \n (or \r\n) is in argument. It's called only if you enabled this feature for the socket.<br />
* OnAccepted - is called for listening socket for every new connection. Arguments are hostname and port of remote end. The callback should return None if you don't need the connection, or reference to new socket, which will be used for this connection.<br />
* OnShutdown - destructor of the socket.<br />
<br />
If callback On* raises an exception, the socket is closed, but if you want to close socket, use method <code>Close</code> instead.<br />
If Init raises an exception, behavior is undefined.<br />
<br />
=== Getting ZNC version ===<br />
If you just want to show ZNC version to humans, usually just <code>znc.CZNC.GetTag()</code> is good.<br />
znc.CZNC.GetTag() # Returns, for example, 'ZNC 0.097 - http:/<nowiki></nowiki>/znc.sourceforge.net'<br />
Check [http://docs.znc.in/ ZNC C++ documentation] for details.<br />
<br />
For getting ZNC version, you can use read following variables:<br />
znc.Version # For example, number 0.097<br />
znc.VersionMajor # 0<br />
znc.VersionMinor # 97<br />
znc.VersionExtra # build-specific string<br />
<br />
<br />
[[Category:Modules]]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ZNC&diff=3114ZNC2024-02-11T00:25:46Z<p>DarthGandalf: Undo revision 3102 by DarthGandalf (talk)</p>
<hr />
<div>__NOTOC__ {{Languages|ZNC}}<br />
<br />
Welcome to the '''ZNC wiki''' where you may find and publish information about '''ZNC''', an advanced [http://en.wikipedia.org/wiki/BNC_%28software%29#IRC IRC bouncer] that is left connected so an IRC client can disconnect/reconnect without losing the chat session. Feel free to update pages which you think are improvable and don't hesitate to ask for help.<br />
<br />
[[File:Overview_network_scheme.png|right]]<br />
[[File:Znc-0.99-black.png|right]]<br />
<br />
You can find us in [ircs://irc.libera.chat:6697/#znc #znc on Libera.Chat]. (New as of May 2021! Our old freenode channel got closed by the new freenode management...)<br />
<br />
== Download ZNC ==<br />
The latest stable release is '''{{ZNC-Version}}''' ([[ChangeLog/{{ZNC-Version}}|ChangeLog]]).<br />
You can find its source '''[https://znc.in/releases/znc-{{ZNC-Version}}.tar.gz <span style="color:#7F0000">here</span>]'''!<br />
<br />
Or you can try testing version, using [https://znc.in/nightly/?C=N&O=D nightly tarball] or [[Git]]{{#if:{{ZNC-Version-Alpha}}|, or '''[https://znc.in/releases/znc-{{ZNC-Version-Alpha}}.tar.gz <span style="color:#7F0000">ZNC {{ZNC-Version-Alpha}}</span>]'''|}}.<br />
<br />
Older versions can be found [https://znc.in/releases/ here].<br />
<br />
Several distros provide ZNC as a package, look at [[Installation]] page for details.<br />
<br />
== How does it work? ==<br />
* [[Installation|Install]] ZNC on your server.<br />
* Generate an initial configuration via <code>znc --makeconf</code>.<br />
** Each ZNC user can connect to several IRC networks, though you'll need to connect your IRC client to ZNC several times (once per network).<br />
** You can later change settings (add more users, tune existing ones, etc.) via the [[webadmin|web interface]] or from [[controlpanel|IRC]].<br />
* Configure your IRC client to connect to your ZNC server.<br />
** If your client has separate '''username''' and '''password''' fields, that works fine.<br />
*** You can set ''username'' as <code>username@clientid/network</code> to connect to a specific network. The network needs to be configured already. Without <code>/network</code> client will be connected to some random network.<br />
** If your client is broken and doesn't support specifying username in well... username, you can use <code>username@clientid/network:password</code> as the ''password''.<br />
** The ''@clientid'' is included with ZNC starting from '''1.6.0'''. This is optional and is the name that you give to your client to recognize it in <code>/msg *status listclients</code>. It's also used by some modules such as [[clientbuffer]] and [[chanfilter]].<br />
* Read the [[FAQ]] if you run into any problems. Feel free to ask on IRC if you need more help.<br />
* Enjoy! (Profit?)<br />
<br />
== Main Features ==<br />
[[Image:Webadmin-settings-dark-clouds.png|thumb|500px|Screenshot of the [[Webadmin]] module in action]]<br />
; [[Modules|Modules]] : ZNC supports dynamic loading of [[Writing modules|C++]], [[modperl|Perl]], [[modpython|Python]] and [[modtcl|Tcl]] modules. To get a list of the available modules and more information follow the link.<br />
; [[Detaching]] : ZNC will remain connected to IRC even while you are offline. You can then reattach later and catch up with what happened while you were gone, and your nick (and operator status) will have been kept for you.<br />
; Multiple Users : You can add additional users under one running process. Useful for public shells that limit background processes.<br />
; Multiple Networks : Each user can connect to several IRC networks at once, with an optional limit configured by ZNC admin.<br />
; [[Multiple clients|Multiple Clients]] : Connect to the same user/network with as many clients as you want.<br />
; Playback Buffers : Stay up-to-date with what happened and when it happened while you were detached, [[timestamps]] are also printed and can be manually configured.<br />
; SSL Support : Encryption for both the listen port and connecting to IRC servers. If your system has OpenSSL, ZNC automatically supports SSL connections.<br />
; IPv6 Support : Both IPv4 and IPv6 address families just work, if your system supports them.<br />
; Web Administration : Using the global [[webadmin]] module, admins can add/remove/edit users and global settings and non admins can edit their own user settings.<br />
<br />
== Getting started ==<br />
* [[Introduction]]<br />
* [[Installation|Download and Installation]]<br />
* [[Connecting to ZNC]]<br />
* [[Using commands|Using ZNC]]<br />
* [[FAQ]]<br />
* [[Providers|Free ZNC providers (if you don't want or cannot install ZNC yourself)]]<br />
<br />
== Further Info ==<br />
* [[Identfile|Setting up ident spoofs via oidentd]]<br />
* [[Chroot]]<br />
* [[ZNC Backup]]<br />
* [[Running ZNC as a system daemon]]<br />
* [[Signed SSL certificate|Using signed SSL cert]]<br />
* [[History]]<br />
* [[Configuration|Configuration parameters]]<br />
* [[Tor|Using with Tor]]<br />
* [[Reverse proxy|Webadmin behind HTTP reverse proxy]]<br />
* [https://github.com/znc/znc/releases.atom Subscribe to new releases]<br />
<br />
=== Writing modules ===<br />
* [[Writing modules|Writing C++ modules]]<br />
* [[modperl|Writing Perl modules]]<br />
* [[modtcl|Writing Tcl modules]]<br />
* [[modpython|Writing Python modules]]<br />
* [[Debugging]]<br />
<br />
=== I want to help, what can I do? ===<br />
That's great! You can:<br />
* send pull requests on [https://github.com/znc/znc github]<br />
* [https://crowdin.com/project/znc-bouncer translate] ZNC to your language<br />
* improve documentation on this wiki<br />
* consult users on our IRC channel<br />
<br />
Talk to us if you have some other ideas.<br />
<br />
=== Internal docs ===<br />
* [[HowToRelease|How to release new ZNC version]]<br />
<br />
== External Links ==<br />
'''Please note that as of February 2011 we have abandoned SourceForge and moved to GitHub.'''<br />
* [https://github.com/znc/znc ZNC project page on GitHub] - report bugs/issues here<br />
* [http://freshmeat.net/projects/znc ZNC on FreshMeat]<br />
* [http://www.openhub.net/p/znc ZNC on OpenHUB]<br />
<br />
[[Category:ZNC]]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Template:ChangeLog&diff=3113Template:ChangeLog2024-02-11T00:20:50Z<p>DarthGandalf: Reverted edit by DarthGandalf (talk) to last revision by Dessa</p>
<hr />
<div><includeonly>{|style="width:100%; font-size:150%;"<br />
|style="text-align:left; width:33%;"| {{#invoke:ChangeLog|prev|this={{{this|{{SUBPAGENAME}}}}}|template=[[ChangeLog/XXX|← XXX]]}}<br />
|style="text-align:center; width:33%;"| ZNC {{{this|{{SUBPAGENAME}}}}}<br />
|style="text-align:right; width:33%;"| {{#invoke:ChangeLog|next|this={{{this|{{SUBPAGENAME}}}}}|template=[[ChangeLog/XXX|XXX →]]}}<br />
|}<br />
{{#switch: {{#invoke:ChangeLog|stability|this={{{this|{{SUBPAGENAME}}}}}}}<br />
| unstable = {{ambox<br />
| style = border-left: 10px solid #F28500; background: #FCE6CC;<br />
| image = [[File:Ambox orange.png|40px]]<br />
| text = This version is not released yet. Use at your own risk.<br />
{{#ifeq:{{#invoke:String|replace|{{ZNC-Version-Alpha}}|{{{this|{{SUBPAGENAME}}}}}|}}|{{ZNC-Version-Alpha}}||<br />
Source tarball of ZNC {{ZNC-Version-Alpha}} is available [https://znc.in/releases/archive/znc-{{ZNC-Version-Alpha}}.tar.gz here].}}<br />
}}<br />
| stable = {{ambox<br />
| style = border-left: 10px solid #4AA02C; background: #C3FDB8;<br />
| image = [[File:Ambox green.png|40px]]<br />
| text = This is the latest release. Source tarball is available [https://znc.in/releases/archive/znc-{{ZNC-Version}}.tar.gz here].<br />
}}<br />
| old = {{ambox<br />
| style = border-left: 10px solid #F28500; background: #FCE6CC;<br />
| image = [[File:Ambox orange.png|40px]]<br />
| text = This is an old ZNC version. If you still use it, please consider upgrading to [[ChangeLog/{{ZNC-Version}}|'''{{ZNC-Version}}''']].<br />
}}<br />
| Error: unknown version {{{this|{{SUBPAGENAME}}}}}, add it to [[Template:ZNC-Versions]]<br />
}}<br />
<br />
{{{category|[[<noinclude>:</noinclude>Category:ChangeLog]]}}}<br />
</includeonly><noinclude>Template for ChangeLog/XXX pages. E.g.: {{ChangeLog|this=1.6.1|category=}}</noinclude></div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3111ChangeLog/1.9.02024-02-10T19:31:23Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
== New ==<br />
* Support for [https://ircv3.net/specs/extensions/capability-negotiation capability negotiation] 302 and <code>cap-notify</code>. ZNC now has API <code>AddServerDependentCapability()</code>, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities ([https://ircv3.net/specs/extensions/away-notify away-notify], [https://ircv3.net/specs/extensions/account-notify account-notify], [https://ircv3.net/specs/extensions/extended-join extended-join]) were moved from the core to a new module: corecaps.<br />
** The [[corecaps]] module is loaded automatically when upgrading from old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x (from git or from nightly tarballs) won't have it loaded automatically, because the existing config states <code>Version = 1.9</code>. In such case you can load it manually. This is to honor choice of users who decide to unload it, since we don't know whether the module is missing intentionally.<br />
** Added support for [https://ircv3.net/specs/extensions/account-tag account-tag] capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to [[wikipedia:Argon2|Argon2id]] (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
* CAP REQ sent by client without CAP LS now suspends the registration as the spec requires {{GH|1820}}<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3107ChangeLog/1.9.02024-02-10T13:07:00Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API <code>AddServerDependentCapability()</code>, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The [[corecaps]] module is loaded automatically when upgrading from old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x (from git or from nightly tarballs) won't have it loaded automatically, because the existing config states <code>Version = 1.9</code>. In such case you can load it manually. This is to honor choice of users who decide to unload it, since we don't know whether the module is missing intentionally.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
* CAP REQ sent by client without CAP LS now suspends the registration as the spec requires {{GH|1820}}<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3106ChangeLog/1.9.02024-02-10T10:34:58Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API <code>AddServerDependentCapability()</code>, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The [[corecaps]] module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x (from git or from nightly tarballs) won't have it loaded automatically, because the existing config states <code>Version = 1.9</code>. In such case you can load it manually. This is to honor choice of users who decide to unload it, since we don't know whether the module is missing intentionally.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
* CAP REQ sent by client without CAP LS now suspends the registration as the spec requires {{GH|1820}}<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3105ChangeLog/1.9.02024-02-10T09:28:30Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API <code>AddServerDependentCapability()</code>, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The [[corecaps]] module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually. This is to honor choice of users who decide to unload it, since we don't know whether the module is missing intentionally.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
* CAP REQ sent by client without CAP LS now suspends the registration as the spec requires {{GH|1820}}<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=HowToRelease&diff=3104HowToRelease2024-02-10T01:16:54Z<p>DarthGandalf: /* To release RC1 */</p>
<hr />
<div>=== Preparation ===<br />
# Check todo lists and bug trackers.<br />
# Update [[:Template:ZNC-Versions]].<br />
# Prepare [[ChangeLog/git]], let everyone check it.<br />
# Move [[ChangeLog/git]] and create that page again.<br />
=== To release RC1 ===<br />
# Update version number in CMakeLists.txt<br />
# (if minor version) make a new branch 1.7.1 from 1.7.x<br />
# commit with message ZNC 1.7.1-rc1.<br />
#* Example: https://github.com/znc/znc/commit/9e4d89aaa4e2b6e5c79600b93665c1c0e0bb5255<br />
# Run <code>./make-tarball.sh 1.7.1-rc1</code><br />
# Test the tarball, publish it.<br />
# Tag the last commit with znc-1.7.1-rc1 (but without annotated tag), push commit and tag to github.<br />
# Set [[:Template:ZNC-Version-Alpha]] to 1.7.1-rc1<br />
<br />
=== Release, release, release ===<br />
# git pull!!!!<br />
# Update version number in CMakeLists.txt, configure.ac and version.h<br />
#* Example: https://github.com/znc/znc/commit/c426898b3a1b899dfe8a8b2a3eeb4b18d8be1bf2<br />
# Update <code>ChangeLog.md</code> based on [[ChangeLog/git]]<br />
# Commit ("Increase the version number to 1.7.1")<br />
# Create tarball (make-tarball.sh 1.7.1)<br />
# Tag the new version in git (Use the changelog as msg, first line is "ZNC 1.7.1")<br />
## git tag -s znc-1.7.1 HEAD<br />
## git push --tags<br />
# Merge 1.7.1 to 1.7.x, delete branch 1.7.1<br />
# (If minor release?) Revert changes to CMakeLists.txt, version.h and configure.ac<br />
#* Example: https://github.com/znc/znc/commit/bae80fd383fa9d75bcc4e891d79248363a6d1d24<br />
# (If major release?) Bump version number to foo+1. (Commit msg: "Increase the version number to foo+1")<br />
# Update the wiki<br />
## Update [[:Template:ZNC-Version]].<br />
## Clear [[:Template:ZNC-Version-Alpha]].<br />
# Upload the release files to znc.in/.<br />
#* Accessible as /srv/znc.in/www/htdocs/ on harpy.<br />
#* The files have to be chgrp's to user group <code>znc</code>!!!<br />
#* The files themselves go directly into <code>archive/</code><br />
#* The main dir only gets symlinks<br />
# Write <code>znc-1.7.1-changelog.txt</code><br />
# Update version number on Wikipedia.<br />
# Update topic on freenode channel<br />
# Update cygwin package using https://github.com/znc/znc-cygwin<br />
# Update docker image using https://github.com/znc/znc-docker and https://github.com/docker-library/official-images</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Template:ChangeLog&diff=3103Template:ChangeLog2024-02-10T01:14:36Z<p>DarthGandalf: Temporarily change URL again</p>
<hr />
<div><includeonly>{|style="width:100%; font-size:150%;"<br />
|style="text-align:left; width:33%;"| {{#invoke:ChangeLog|prev|this={{{this|{{SUBPAGENAME}}}}}|template=[[ChangeLog/XXX|← XXX]]}}<br />
|style="text-align:center; width:33%;"| ZNC {{{this|{{SUBPAGENAME}}}}}<br />
|style="text-align:right; width:33%;"| {{#invoke:ChangeLog|next|this={{{this|{{SUBPAGENAME}}}}}|template=[[ChangeLog/XXX|XXX →]]}}<br />
|}<br />
{{#switch: {{#invoke:ChangeLog|stability|this={{{this|{{SUBPAGENAME}}}}}}}<br />
| unstable = {{ambox<br />
| style = border-left: 10px solid #F28500; background: #FCE6CC;<br />
| image = [[File:Ambox orange.png|40px]]<br />
| text = This version is not released yet. Use at your own risk.<br />
{{#ifeq:{{#invoke:String|replace|{{ZNC-Version-Alpha}}|{{{this|{{SUBPAGENAME}}}}}|}}|{{ZNC-Version-Alpha}}||<br />
Source tarball of ZNC {{ZNC-Version-Alpha}} is available [http://people.znc.in/~darthgandalf/znc/znc-{{ZNC-Version-Alpha}}.tar.gz here].}}<br />
}}<br />
| stable = {{ambox<br />
| style = border-left: 10px solid #4AA02C; background: #C3FDB8;<br />
| image = [[File:Ambox green.png|40px]]<br />
| text = This is the latest release. Source tarball is available [https://znc.in/releases/archive/znc-{{ZNC-Version}}.tar.gz here].<br />
}}<br />
| old = {{ambox<br />
| style = border-left: 10px solid #F28500; background: #FCE6CC;<br />
| image = [[File:Ambox orange.png|40px]]<br />
| text = This is an old ZNC version. If you still use it, please consider upgrading to [[ChangeLog/{{ZNC-Version}}|'''{{ZNC-Version}}''']].<br />
}}<br />
| Error: unknown version {{{this|{{SUBPAGENAME}}}}}, add it to [[Template:ZNC-Versions]]<br />
}}<br />
<br />
{{{category|[[<noinclude>:</noinclude>Category:ChangeLog]]}}}<br />
</includeonly><noinclude>Template for ChangeLog/XXX pages. E.g.: {{ChangeLog|this=1.6.1|category=}}</noinclude></div>DarthGandalfhttps://wiki.znc.in/index.php?title=ZNC&diff=3102ZNC2024-02-10T01:11:53Z<p>DarthGandalf: /* Download ZNC */ Temporary change tarballs URL again</p>
<hr />
<div>__NOTOC__ {{Languages|ZNC}}<br />
<br />
Welcome to the '''ZNC wiki''' where you may find and publish information about '''ZNC''', an advanced [http://en.wikipedia.org/wiki/BNC_%28software%29#IRC IRC bouncer] that is left connected so an IRC client can disconnect/reconnect without losing the chat session. Feel free to update pages which you think are improvable and don't hesitate to ask for help.<br />
<br />
[[File:Overview_network_scheme.png|right]]<br />
[[File:Znc-0.99-black.png|right]]<br />
<br />
You can find us in [ircs://irc.libera.chat:6697/#znc #znc on Libera.Chat]. (New as of May 2021! Our old freenode channel got closed by the new freenode management...)<br />
<br />
== Download ZNC ==<br />
The latest stable release is '''{{ZNC-Version}}''' ([[ChangeLog/{{ZNC-Version}}|ChangeLog]]).<br />
You can find its source '''[https://znc.in/releases/znc-{{ZNC-Version}}.tar.gz <span style="color:#7F0000">here</span>]'''!<br />
<br />
Or you can try testing version, using [https://znc.in/nightly/?C=N&O=D nightly tarball] or [[Git]]{{#if:{{ZNC-Version-Alpha}}|, or '''[http://people.znc.in/~darthgandalf/znc/ <span style="color:#7F0000">ZNC {{ZNC-Version-Alpha}}</span>]'''|}}.<br />
<br />
Older versions can be found [https://znc.in/releases/ here].<br />
<br />
Several distros provide ZNC as a package, look at [[Installation]] page for details.<br />
<br />
== How does it work? ==<br />
* [[Installation|Install]] ZNC on your server.<br />
* Generate an initial configuration via <code>znc --makeconf</code>.<br />
** Each ZNC user can connect to several IRC networks, though you'll need to connect your IRC client to ZNC several times (once per network).<br />
** You can later change settings (add more users, tune existing ones, etc.) via the [[webadmin|web interface]] or from [[controlpanel|IRC]].<br />
* Configure your IRC client to connect to your ZNC server.<br />
** If your client has separate '''username''' and '''password''' fields, that works fine.<br />
*** You can set ''username'' as <code>username@clientid/network</code> to connect to a specific network. The network needs to be configured already. Without <code>/network</code> client will be connected to some random network.<br />
** If your client is broken and doesn't support specifying username in well... username, you can use <code>username@clientid/network:password</code> as the ''password''.<br />
** The ''@clientid'' is included with ZNC starting from '''1.6.0'''. This is optional and is the name that you give to your client to recognize it in <code>/msg *status listclients</code>. It's also used by some modules such as [[clientbuffer]] and [[chanfilter]].<br />
* Read the [[FAQ]] if you run into any problems. Feel free to ask on IRC if you need more help.<br />
* Enjoy! (Profit?)<br />
<br />
== Main Features ==<br />
[[Image:Webadmin-settings-dark-clouds.png|thumb|500px|Screenshot of the [[Webadmin]] module in action]]<br />
; [[Modules|Modules]] : ZNC supports dynamic loading of [[Writing modules|C++]], [[modperl|Perl]], [[modpython|Python]] and [[modtcl|Tcl]] modules. To get a list of the available modules and more information follow the link.<br />
; [[Detaching]] : ZNC will remain connected to IRC even while you are offline. You can then reattach later and catch up with what happened while you were gone, and your nick (and operator status) will have been kept for you.<br />
; Multiple Users : You can add additional users under one running process. Useful for public shells that limit background processes.<br />
; Multiple Networks : Each user can connect to several IRC networks at once, with an optional limit configured by ZNC admin.<br />
; [[Multiple clients|Multiple Clients]] : Connect to the same user/network with as many clients as you want.<br />
; Playback Buffers : Stay up-to-date with what happened and when it happened while you were detached, [[timestamps]] are also printed and can be manually configured.<br />
; SSL Support : Encryption for both the listen port and connecting to IRC servers. If your system has OpenSSL, ZNC automatically supports SSL connections.<br />
; IPv6 Support : Both IPv4 and IPv6 address families just work, if your system supports them.<br />
; Web Administration : Using the global [[webadmin]] module, admins can add/remove/edit users and global settings and non admins can edit their own user settings.<br />
<br />
== Getting started ==<br />
* [[Introduction]]<br />
* [[Installation|Download and Installation]]<br />
* [[Connecting to ZNC]]<br />
* [[Using commands|Using ZNC]]<br />
* [[FAQ]]<br />
* [[Providers|Free ZNC providers (if you don't want or cannot install ZNC yourself)]]<br />
<br />
== Further Info ==<br />
* [[Identfile|Setting up ident spoofs via oidentd]]<br />
* [[Chroot]]<br />
* [[ZNC Backup]]<br />
* [[Running ZNC as a system daemon]]<br />
* [[Signed SSL certificate|Using signed SSL cert]]<br />
* [[History]]<br />
* [[Configuration|Configuration parameters]]<br />
* [[Tor|Using with Tor]]<br />
* [[Reverse proxy|Webadmin behind HTTP reverse proxy]]<br />
* [https://github.com/znc/znc/releases.atom Subscribe to new releases]<br />
<br />
=== Writing modules ===<br />
* [[Writing modules|Writing C++ modules]]<br />
* [[modperl|Writing Perl modules]]<br />
* [[modtcl|Writing Tcl modules]]<br />
* [[modpython|Writing Python modules]]<br />
* [[Debugging]]<br />
<br />
=== I want to help, what can I do? ===<br />
That's great! You can:<br />
* send pull requests on [https://github.com/znc/znc github]<br />
* [https://crowdin.com/project/znc-bouncer translate] ZNC to your language<br />
* improve documentation on this wiki<br />
* consult users on our IRC channel<br />
<br />
Talk to us if you have some other ideas.<br />
<br />
=== Internal docs ===<br />
* [[HowToRelease|How to release new ZNC version]]<br />
<br />
== External Links ==<br />
'''Please note that as of February 2011 we have abandoned SourceForge and moved to GitHub.'''<br />
* [https://github.com/znc/znc ZNC project page on GitHub] - report bugs/issues here<br />
* [http://freshmeat.net/projects/znc ZNC on FreshMeat]<br />
* [http://www.openhub.net/p/znc ZNC on OpenHUB]<br />
<br />
[[Category:ZNC]]</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Template:ZNC-Version-Alpha&diff=3101Template:ZNC-Version-Alpha2024-02-10T01:09:37Z<p>DarthGandalf: </p>
<hr />
<div>1.9.0-rc1</div>DarthGandalfhttps://wiki.znc.in/index.php?title=HowToRelease&diff=3100HowToRelease2024-02-10T00:58:13Z<p>DarthGandalf: /* To release RC1 */</p>
<hr />
<div>=== Preparation ===<br />
# Check todo lists and bug trackers.<br />
# Update [[:Template:ZNC-Versions]].<br />
# Prepare [[ChangeLog/git]], let everyone check it.<br />
# Move [[ChangeLog/git]] and create that page again.<br />
=== To release RC1 ===<br />
# Update version number in CMakeLists.txt, make a new branch 1.7.1 from 1.7.x, commit with message ZNC 1.7.1-rc1. (probably version.h should mention -rc1 in VERSION_STR?)<br />
#* Example: https://github.com/znc/znc/commit/9e4d89aaa4e2b6e5c79600b93665c1c0e0bb5255<br />
# Run <code>./make-tarball.sh 1.7.1-rc1</code><br />
# Test the tarball, publish it.<br />
# Tag the last commit with znc-1.7.1-rc1 (but without annotated tag), push commit and tag to github.<br />
# Set [[:Template:ZNC-Version-Alpha]] to 1.7.1-rc1<br />
<br />
=== Release, release, release ===<br />
# git pull!!!!<br />
# Update version number in CMakeLists.txt, configure.ac and version.h<br />
#* Example: https://github.com/znc/znc/commit/c426898b3a1b899dfe8a8b2a3eeb4b18d8be1bf2<br />
# Update <code>ChangeLog.md</code> based on [[ChangeLog/git]]<br />
# Commit ("Increase the version number to 1.7.1")<br />
# Create tarball (make-tarball.sh 1.7.1)<br />
# Tag the new version in git (Use the changelog as msg, first line is "ZNC 1.7.1")<br />
## git tag -s znc-1.7.1 HEAD<br />
## git push --tags<br />
# Merge 1.7.1 to 1.7.x, delete branch 1.7.1<br />
# (If minor release?) Revert changes to CMakeLists.txt, version.h and configure.ac<br />
#* Example: https://github.com/znc/znc/commit/bae80fd383fa9d75bcc4e891d79248363a6d1d24<br />
# (If major release?) Bump version number to foo+1. (Commit msg: "Increase the version number to foo+1")<br />
# Update the wiki<br />
## Update [[:Template:ZNC-Version]].<br />
## Clear [[:Template:ZNC-Version-Alpha]].<br />
# Upload the release files to znc.in/.<br />
#* Accessible as /srv/znc.in/www/htdocs/ on harpy.<br />
#* The files have to be chgrp's to user group <code>znc</code>!!!<br />
#* The files themselves go directly into <code>archive/</code><br />
#* The main dir only gets symlinks<br />
# Write <code>znc-1.7.1-changelog.txt</code><br />
# Update version number on Wikipedia.<br />
# Update topic on freenode channel<br />
# Update cygwin package using https://github.com/znc/znc-cygwin<br />
# Update docker image using https://github.com/znc/znc-docker and https://github.com/docker-library/official-images</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3099ChangeLog/1.9.02024-02-10T00:55:47Z<p>DarthGandalf: /* Fixes */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The [[corecaps]] module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually. This is to honor choice of users who decide to unload it, since we don't know whether the module is missing intentionally.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
* CAP REQ sent by client without CAP LS now suspends the registration as the spec requires {{GH|1820}}<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3095ChangeLog/1.9.02024-02-09T23:49:37Z<p>DarthGandalf: /* Fixes */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually. This is to honor choice of users who decide to unload it, since we don't know whether the module is missing intentionally.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3094ChangeLog/1.9.02024-02-09T23:48:16Z<p>DarthGandalf: </p>
<hr />
<div>{{ChangeLog}}<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually. This is to honor choice of users who decide to unload it, since we don't know whether the module is missing intentionally.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3093ChangeLog/1.9.02024-02-09T23:43:25Z<p>DarthGandalf: </p>
<hr />
<div>{{ChangeLog}}<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/git&diff=3092ChangeLog/git2024-02-09T23:43:04Z<p>DarthGandalf: Created page with "{{ChangeLog}} <!-- The following is generated via this command: HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-1.9.0..$HEAD | cat --> <!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --> See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable. == New == == Fixes == == Modules == == Notes for package maintainers == == Inter..."</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-1.9.0..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
== Fixes ==<br />
== Modules ==<br />
== Notes for package maintainers ==<br />
== Internal ==</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3091ChangeLog/1.9.02024-02-09T23:42:04Z<p>DarthGandalf: DarthGandalf moved page ChangeLog/git to ChangeLog/1.9.0 without leaving a redirect</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=Template:ZNC-Versions&diff=3090Template:ZNC-Versions2024-02-09T23:41:07Z<p>DarthGandalf: </p>
<hr />
<div>0.000<br />
0.043<br />
0.044<br />
0.045<br />
0.047<br />
0.050<br />
0.052<br />
0.054<br />
0.056<br />
0.058<br />
0.060<br />
0.062<br />
0.064<br />
0.066<br />
0.068<br />
0.070<br />
0.072<br />
0.074<br />
0.076<br />
0.078<br />
0.080<br />
0.090<br />
0.092<br />
0.094<br />
0.096<br />
0.098<br />
0.200<br />
0.202<br />
0.204<br />
0.206<br />
1.0<br />
1.2<br />
1.4<br />
1.6.0<br />
1.6.1<br />
1.6.2<br />
1.6.3<br />
1.6.4<br />
1.6.5<br />
1.6.6<br />
1.7.0<br />
1.7.1<br />
1.7.2<br />
1.7.3<br />
1.7.4<br />
1.7.5<br />
1.8.0<br />
1.8.1<br />
1.8.2<br />
1.9.0<br />
git</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3089ChangeLog/1.9.02024-02-09T23:40:31Z<p>DarthGandalf: /* Internal */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: removed legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3088ChangeLog/1.9.02024-02-09T23:38:10Z<p>DarthGandalf: /* Modules */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** Added Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** Route replies to /topic<br />
* [[sasl]]: Don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fixed order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3087ChangeLog/1.9.02024-02-09T23:37:12Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically. In such case you can load it manually.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** route replies to /topic<br />
* [[sasl]]: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fix order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3086ChangeLog/1.9.02024-02-09T23:36:28Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
*** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** route replies to /topic<br />
* [[sasl]]: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fix order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3085ChangeLog/1.9.02024-02-09T23:36:13Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically.<br />
** Added support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** route replies to /topic<br />
* [[sasl]]: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fix order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3084ChangeLog/1.9.02024-02-09T23:36:01Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** The corecaps module is loaded automatically when using old config and when creating new config, but it's possible to unload it.<br />
** Note: users who were using pre-release versions of 1.9.x from git won't have it loaded automatically.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** route replies to /topic<br />
* [[sasl]]: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fix order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3083ChangeLog/1.9.02024-02-09T08:59:34Z<p>DarthGandalf: /* Notes for package maintainers */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** route replies to /topic<br />
* [[sasl]]: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fix order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leaving only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. You can use either <code>configure</code> as before, or CMake directly. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3082ChangeLog/1.9.02024-02-09T08:58:40Z<p>DarthGandalf: /* Modules */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: In some cases settings were parsed incorrectly, resulting in failure to do the autoop, now it's fixed<br />
* [[clientnotify]]: Added options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: Fixed help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: Allow overriding label for timers, which means now there can be more than 1 timer per module<br />
* [[modpython]]:<br />
** Rewrote internals of how modpython loads modules. {{GH|1724}}<br />
*** Main motivation for the switch from using <code>imp</code> to using <code>importlib</code> was to support Python 3.12+.<br />
*** As an additional benefit, now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files).<br />
*** All the old python modules should load as they were before.<br />
*** ZNC no longer supports loading a C python extension directly through modpython (though I doubt there were any users of that obscure feature): if you want to some parts of the module to be compiled, you can always import that from <code>__init__.py</code>.<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** route replies to /topic<br />
* [[sasl]]: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fix order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3081ChangeLog/1.9.02024-02-09T08:42:13Z<p>DarthGandalf: /* Modules */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* [[autoop]]: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* [[clientnotify]]: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* [[controlpanel]]: fix in help output<br />
* [[log]]: Log nickserv account in the joins lines. {{GH|1870}}<br />
* [[modperl]]: allow overriding timer label<br />
* [[modpython]]:<br />
** Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
** Implemented Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* [[route_replies]]:<br />
** add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
** route replies to /topic<br />
* [[sasl]]: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* [[webadmin]]: Fix order of breadcrumbs in network page<br />
* [[watch]]: Allow new entries to use spaces {{GH|1822}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3080ChangeLog/1.9.02024-02-09T02:58:32Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* Added Portuguese and Turkish translations<br />
* znc-buildmod: output where the module was written to<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* controlpanel: fix in help output<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3079ChangeLog/1.9.02024-02-09T02:58:13Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New user options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* controlpanel: fix in help output<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3078ChangeLog/1.9.02024-02-09T02:57:54Z<p>DarthGandalf: /* Notes for package maintainers */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* controlpanel: fix in help output<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Removed autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Dropped support for Python < 3.4<br />
* Dropped support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3077ChangeLog/1.9.02024-02-09T02:57:17Z<p>DarthGandalf: /* Internal */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* controlpanel: fix in help output<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Remove autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Drop support for Python < 3.4<br />
* Drop support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Switched to steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Made <code>CUser::Put...()</code> send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* List of translators is now automatically generated from Crowdin<br />
* Modernized the way how CMake is used<br />
* Updated default SSL settings from Mozilla recommmendations<br />
* Rewrote message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Web: remove legacy xhtml syntax {{GH|1723}}<br />
* Documented more functions<br />
* Made some integration tests run faster by changing ServerThrottle value in the test</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3076ChangeLog/1.9.02024-02-09T02:53:55Z<p>DarthGandalf: /* Fixes */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Fixed build with SWIG 4.2.0<br />
* Fixed build with LibreSSL {{GH|1828}}<br />
* Fixed crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Fixed handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Stopped sending invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fixed an ODR violation {{GH|1835}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* controlpanel: fix in help output<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Remove autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Drop support for Python < 3.4<br />
* Drop support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Document more functions.<br />
* Use steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Modernized the way how CMake is used<br />
* Make some integration tests run faster by changing ServerThrottle value<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* Various fixes to CI<br />
* Generate list of translators automatically from Crowdin<br />
* Update default SSL settings from Mozilla recommmendations<br />
* Rewrite message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Make CUser::Put* send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Web: remove legacy xhtml syntax {{GH|1723}}</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3075ChangeLog/1.9.02024-02-09T02:51:08Z<p>DarthGandalf: /* New */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
** Several capabilities (away-notify, account-notify, extended-join) were moved from the core to a new module: corecaps.<br />
** Add support for account-tag capability, also in corecaps module {{GH|1746}}<br />
* Updated password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Don't send invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fix build with SWIG 4.2.0<br />
* Fix handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Don't crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Fix an ODR violation {{GH|1835}}<br />
* Fix build with LibreSSL {{GH|1828}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* controlpanel: fix in help output<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Remove autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Drop support for Python < 3.4<br />
* Drop support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Document more functions.<br />
* Use steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Modernized the way how CMake is used<br />
* Make some integration tests run faster by changing ServerThrottle value<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* Various fixes to CI<br />
* Generate list of translators automatically from Crowdin<br />
* Update default SSL settings from Mozilla recommmendations<br />
* Rewrite message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Make CUser::Put* send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Web: remove legacy xhtml syntax {{GH|1723}}</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3074ChangeLog/1.9.02024-02-09T02:43:56Z<p>DarthGandalf: /* Notes for package maintainers */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Update password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
* Add support for cap account-tag {{GH|1746}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Don't send invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fix build with SWIG 4.2.0<br />
* Fix handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Don't crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Fix an ODR violation {{GH|1835}}<br />
* Fix build with LibreSSL {{GH|1828}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* controlpanel: fix in help output<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Remove autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Drop support for Python < 3.4<br />
* Drop support for SWIG < 4.0.1<br />
* The systemd unit now passes <code>--datadir=/var/lib/znc</code><br />
<br />
== Internal ==<br />
* Document more functions.<br />
* Use steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Modernized the way how CMake is used<br />
* Make some integration tests run faster by changing ServerThrottle value<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* Various fixes to CI<br />
* Generate list of translators automatically from Crowdin<br />
* Update default SSL settings from Mozilla recommmendations<br />
* Rewrite message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Make CUser::Put* send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Web: remove legacy xhtml syntax {{GH|1723}}</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3073ChangeLog/1.9.02024-02-09T02:41:54Z<p>DarthGandalf: </p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Update password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
* Add support for cap account-tag {{GH|1746}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Don't send invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fix build with SWIG 4.2.0<br />
* Fix handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Don't crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Fix an ODR violation {{GH|1835}}<br />
* Fix build with LibreSSL {{GH|1828}}<br />
* Better hide password in PASS debug lines, sometimes it was not hidden<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}} {{GH|1833}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
* controlpanel: fix in help output<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Remove autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Drop support for Python < 3.4<br />
* Drop support for SWIG < 4.0.1<br />
* Set the --datadir path in systemd unit to /var/lib/znc instead of assuming that $HOME is set correctly<br />
<br />
== Internal ==<br />
* Document more functions.<br />
* Use steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Modernized the way how CMake is used<br />
* Make some integration tests run faster by changing ServerThrottle value<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* Various fixes to CI<br />
* Generate list of translators automatically from Crowdin<br />
* Update default SSL settings from Mozilla recommmendations<br />
* Rewrite message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Make CUser::Put* send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
* Web: remove legacy xhtml syntax {{GH|1723}}</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3072ChangeLog/1.9.02024-02-09T02:26:12Z<p>DarthGandalf: </p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Update password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
* Add support for cap account-tag {{GH|1746}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Don't send invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fix build with SWIG 4.2.0<br />
* Fix handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Don't crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Fix an ODR violation {{GH|1835}}<br />
* Fix build with LibreSSL {{GH|1828}}<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
* route_replies: route replies to /topic<br />
* modperl: allow overriding timer label<br />
* autoop: in some cases settings were parsed incorrectly, resulting in failure to do the autoop<br />
* sasl: don't forward 908 (RPL_SASLMECHS) to clients {{GH|1756}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Remove autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Drop support for Python < 3.4<br />
* Drop support for SWIG < 4.0.1<br />
* Set the --datadir path in systemd unit to /var/lib/znc instead of assuming that $HOME is set correctly<br />
<br />
== Internal ==<br />
* Document more functions.<br />
* Use steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Modernized the way how CMake is used<br />
* Make some integration tests run faster by changing ServerThrottle value<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* Various fixes to CI<br />
* Generate list of translators automatically from Crowdin<br />
* Update default SSL settings from Mozilla recommmendations<br />
* Rewrite message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Make CUser::Put* send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
<br />
== TODO: to triage ==<br />
* Test module translation of commands {{git|9c855b5c}}<br />
* Rename cmd/desc to command/description {{git|e0c05ddb}}<br />
* Fixed missing paragraph closing tag {{git|2a733cc9}}<br />
* Hide password in PASS debug lines without : in trailing param {{git|e7b6a771}}<br />
* Fix controlpanel output {{git|4393b9d9}}<br />
* Web: remove legacy xhtml syntax (#1723) {{git|17ec6095}}<br />
* Fix PY_SSIZE_T_CLEAN python warning {{git|e8ff1612}}</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3071ChangeLog/1.9.02024-02-09T01:44:41Z<p>DarthGandalf: /* Notes for package maintainers (TODO) */</p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Update password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
* Add support for cap account-tag {{GH|1746}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Don't send invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fix build with SWIG 4.2.0<br />
* Fix handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Don't crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Fix an ODR violation {{GH|1835}}<br />
* Fix build with LibreSSL {{GH|1828}}<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
<br />
== Notes for package maintainers ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Remove autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Drop support for Python < 3.4<br />
* Drop support for SWIG < 4.0.1<br />
<br />
== Internal ==<br />
* Document more functions.<br />
* Use steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Modernized the way how CMake is used<br />
* Make some integration tests run faster by changing ServerThrottle value<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* Various fixes to CI<br />
* Generate list of translators automatically from Crowdin<br />
* Update default SSL settings from Mozilla recommmendations<br />
* Rewrite message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Make CUser::Put* send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
<br />
== TODO: to triage ==<br />
* Test module translation of commands {{git|9c855b5c}}<br />
* Rename cmd/desc to command/description {{git|e0c05ddb}}<br />
* Fixed missing paragraph closing tag {{git|2a733cc9}}<br />
* Hide password in PASS debug lines without : in trailing param {{git|e7b6a771}}<br />
* route_replies: route TOPIC requests to client {{git|9ff9fa7c}}<br />
* Fix controlpanel output {{git|4393b9d9}}<br />
* change message when staying in foreground {{git|57c94b8b}}<br />
* Fix path in systemd service (which shouldn't be here at all) {{git|d4bfd143}}<br />
* WIP fix autotop {{git|38081d5a}}<br />
* sasl: don't forward 908 numeric to clienT {{git|f9fc9b40}}<br />
* modperl: allow overriding timer label {{git|1c9cb3f8}}<br />
* Web: remove legacy xhtml syntax (#1723) {{git|17ec6095}}<br />
* Fix PY_SSIZE_T_CLEAN python warning {{git|e8ff1612}}</div>DarthGandalfhttps://wiki.znc.in/index.php?title=ChangeLog/1.9.0&diff=3070ChangeLog/1.9.02024-02-09T01:44:26Z<p>DarthGandalf: </p>
<hr />
<div>{{ChangeLog}}<br />
<br />
<!-- The following is generated via this command:<br />
HEAD=$(git rev-parse master) ; echo "Last update at $HEAD" ; echo ; git log --format='* %s {{git|%h}}' --no-merges znc-0.098..$HEAD | cat<br />
--><br />
<br />
<!-- Last update at eb607b9736386844dc1aac6005d6ec95e270f0c0 --><br />
<br />
See https://github.com/znc/znc/compare/znc-{{ZNC-Version}}...master for a list of changes since {{ZNC-Version}} stable.<br />
<br />
== New ==<br />
* Update password hashing algorithm from SHA-256 to Argon2id (if libargon2 is installed). Existing passwords are transparently upgraded upon login. {{GH|1879}}<br />
* Support for capability negotiation 3.2 and <code>cap-notify</code>. ZNC now has API, using which modules can easily implement new capabilities: if server supports a cap, it will automatically be offered to clients which support <code>cap-notify</code> and ZNC will notify the module when the capability is enabled or disabled for server and for each client. {{GH|1859}}<br />
* Add support for cap account-tag {{GH|1746}}<br />
* New User Options: DenySetIdent, DenySetNetwork, DenySetRealName, DenySetQuitMsg, DenySetCTCPReplies {{GH|1814}}<br />
* Switch --makeconf wizard default network from freenode to Libera<br />
* znc-buildmod: output where the module was written to<br />
* Allow ordering of channels: via ListChans, MoveChan and SwapChans commands, and via webadmin {{GH|1744}}<br />
* Add Portuguese and Turkish translations<br />
<br />
== Fixes ==<br />
* Don't send invalid 333 (RPL_TOPICWHOTIME) to client if topic owner is unknown {{GH|1889}}<br />
* Fix build with SWIG 4.2.0<br />
* Fix handling of timezones when parsing server-time tags received from server {{GH|1857}} {{GH|1773}}<br />
* Don't crash when receiving SASL lines from server without having negotiated SASL via CAP<br />
* Use module names as the module ident, otherwise some clients were merging conversations with different modules together. {{GH|1874}}<br />
* Fix an ODR violation {{GH|1835}}<br />
* Fix build with LibreSSL {{GH|1828}}<br />
<br />
== Modules ==<br />
* modpython: Rewrite how modpython loads modules from <code>imp</code> to <code>importlib</code>: this adds support for Python 3.12. Also now it's possible to structure the module as a python package (a subdirectory with <code>__init__.py</code> and other .py files), however it no longer supports loading a C python extension through modpython - just write the module on C++ in such case instead of python, or use the <code>__init__.py</code> format and implement some of the files in C. {{GH|1724}}<br />
* log: Add account to joins for the log module. {{GH|1870}}<br />
* clientnotify: Add options to reduce amount of notifications depending on the IP and the client ID of the connecting client {{GH|1843}}<br />
* modpython: Implement Module.AddCommand() {{GH|1832}}<br />
* webadmin: Fix order of breadcrumbs in network page<br />
* watch: Allow new entries to use spaces {{GH|1822}}<br />
* route_replies: add Solanum-specific 337 (RPL_WHOISTEXT) to possible replies of /whois {{GH|1881}}<br />
<br />
== Notes for package maintainers (TODO) ==<br />
* Require C++17 compiler. That is, GCC 8+ or Clang 5+. {{GH|1887}}<br />
* Remove autoconf, leave only CMake as the build system. The <code>configure</code> script is now merely a wrapper for CMake, and accepts mostly the same parameters as the old <code>configure</code>. Minimum supported CMake version is 3.13.<br />
* If cctz library is available on the system, it will be used, otherwise the bundled copy will be used<br />
* libargon2 is new optional dependency<br />
* Drop support for Python < 3.4<br />
* Drop support for SWIG < 4.0.1<br />
<br />
== Internal ==<br />
* Document more functions.<br />
* Use steady clock for cache map and for sockets to fix certain issues with leap seconds and DST<br />
* Modernized the way how CMake is used<br />
* Make some integration tests run faster by changing ServerThrottle value<br />
* Setup Github Actions to replace old Travis CI setup<br />
* Added CIFuzz {{GH|1845}}<br />
* Added CodeQL {{GH|1846}}<br />
* Various fixes to CI<br />
* Generate list of translators automatically from Crowdin<br />
* Update default SSL settings from Mozilla recommmendations<br />
* Rewrite message parsing using std::string_view, improving the performance of the parser {{GH|1785}}<br />
* Make CUser::Put* send to all clients instead of only networkless clients. Deprecate CUser::PutAllUser()<br />
<br />
== TODO: to triage ==<br />
* Test module translation of commands {{git|9c855b5c}}<br />
* Rename cmd/desc to command/description {{git|e0c05ddb}}<br />
* Fixed missing paragraph closing tag {{git|2a733cc9}}<br />
* Hide password in PASS debug lines without : in trailing param {{git|e7b6a771}}<br />
* route_replies: route TOPIC requests to client {{git|9ff9fa7c}}<br />
* Fix controlpanel output {{git|4393b9d9}}<br />
* change message when staying in foreground {{git|57c94b8b}}<br />
* Fix path in systemd service (which shouldn't be here at all) {{git|d4bfd143}}<br />
* WIP fix autotop {{git|38081d5a}}<br />
* sasl: don't forward 908 numeric to clienT {{git|f9fc9b40}}<br />
* modperl: allow overriding timer label {{git|1c9cb3f8}}<br />
* Web: remove legacy xhtml syntax (#1723) {{git|17ec6095}}<br />
* Fix PY_SSIZE_T_CLEAN python warning {{git|e8ff1612}}</div>DarthGandalf