diff options
| author | 2019-03-30 22:06:19 +0000 | |
|---|---|---|
| committer | 2019-03-30 22:06:19 +0000 | |
| commit | 1fff2f7f87fa0e69494fe45902cfa315204d1e43 (patch) | |
| tree | b4f3eac01dc458cc7f3ab5b43a57c44d06044bed | |
| parent | Remove the flashpolicyd module. (diff) | |
| parent | Rename OnClientProtocolPopulateTags to OnPopulateTags. (diff) | |
Merge branch 'insp3' into master.
123 files changed, 1414 insertions, 590 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 6fdf33bba..ea6121d99 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -14,7 +14,7 @@ Example configs: 3.0 (alpha) - https://github.com/inspircd/inspircd/tree/master/docs/conf Wiki: -https://wiki.inspircd.org/ +https://wiki.inspircd.org --> **Description** @@ -268,7 +268,7 @@ not been tested as heavily and may contain various faults which could seriously affect the running of your server. It is recommended that you use a stable version instead. -You can obtain the latest stable version from http://www.inspircd.org/ or by +You can obtain the latest stable version from https://www.inspircd.org or by running `<|GREEN git checkout $(git describe --abbrev=0 --tags insp3)|>` if you are installing from Git. EOW diff --git a/docs/conf/filter.conf.example b/docs/conf/filter.conf.example index 29e1f530c..f9afc85a8 100644 --- a/docs/conf/filter.conf.example +++ b/docs/conf/filter.conf.example @@ -16,8 +16,8 @@ # block This blocks the line, sends out a notice to all opers with # +s and informs the user that their message was blocked. # -# silent This blocks the line only, and informs the user their message -# was blocked, but does not notify opers. +# silent This blocks the line only, and informs the user that their +# message was blocked, but does not notify opers. # # none This action causes nothing to be done except logging. This # is the default action if none is specified. @@ -26,17 +26,17 @@ # the kill reason. # # gline G-line the user for 'duration' length of time. Durations may -# be specified using the notation 1y2d3h4m6s in a similar way to +# be specified using the notation 1y2w3d4h5m6s in a similar way to # other G-lines, omitting the duration or setting it to 0 makes # any G-lines set by this filter be permanent. # # zline Z-line the user for 'duration' length of time. Durations may -# be specified using the notation 1y2d3h4m6s in a similar way to +# be specified using the notation 1y2w3d4h5m6s in a similar way to # other Z-lines, omitting the duration or setting it to 0 makes # any Z-lines set by this filter be permanent. # # shun Shun the user for 'duration' length of time. Durations may -# be specified using the notation 1y2d3h4m6s in a similar way to +# be specified using the notation 1y2w3d4h5m6s in a similar way to # other X-lines, omitting the duration or setting it to 0 makes # any shuns set by this filter be permanent. # Requires the shun module to be loaded. @@ -59,11 +59,11 @@ # # <keyword pattern="*qwerty*" reason="You qwertied!" action="block" flags="pn"> # <keyword pattern="*killmenow*" reason="As you request." action="kill" flags="*"> -# <keyword pattern="*blah*" reason="Dont blah!" action="gline" duration="1d6h" flags="-"> +# <keyword pattern="*blah*" reason="Don't blah!" action="gline" duration="1d6h" flags="-"> # An example regexp filter: # -# <keyword pattern="^blah.*?$" reason="Dont blah!" action="gline" duration="1d6h" flags="pnPq"> +# <keyword pattern="^blah.*?$" reason="Don't blah!" action="gline" duration="1d6h" flags="pnPq"> # You may specify specific channels that are exempt from being filtered: #<exemptfromfilter target="#opers"> diff --git a/docs/conf/helpop.conf.example b/docs/conf/helpop.conf.example index bd184f6ef..f8689c7b4 100644 --- a/docs/conf/helpop.conf.example +++ b/docs/conf/helpop.conf.example @@ -3,7 +3,7 @@ # or you can customize the responses for your network and/or add more. # # The way the new helpop system works is simple. You use one or more helpop tags. -# <helpop key="moo" value="something here">. +# <helpop key="moo" value="something here"> # key is what the user is looking for (i.e. /helpop moo), and value is what they get back # (note that it can span multiple lines!). # -- w00t 16/dec/2006 @@ -34,14 +34,14 @@ parameter for this command. ACCEPT ADMIN AWAY COMMANDS CYCLE DCCALLOW FPART INFO INVITE ISON JOIN KICK KNOCK LINKS LIST LUSERS MAP MKPASSWD -MODE MODULES MOTD NAMES NICK NOTICE -OPER PART PASS PING PONG PRIVMSG -QUIT REMOVE SETNAME SILENCE SQUERY SSLINFO -STATS TBAN TIME TITLE TOPIC UNINVITE -USER USERHOST VERSION VHOST WATCH WHO -WHOIS WHOWAS"> +MODE MODULES MONITOR MOTD NAMES NICK +NOTICE OPER PART PASS PING PONG +PRIVMSG QUIT REMOVE SETNAME SILENCE SQUERY +SSLINFO STATS TBAN TIME TITLE TOPIC +UNINVITE USER USERHOST VERSION VHOST WATCH +WHO WHOIS WHOWAS"> -<helpop key="squery" value="/SQUERY <target> <text> +<helpop key="squery" value="/SQUERY <target> :<message> Sends a message to the network service specified in <target>."> @@ -57,76 +57,103 @@ Uninvite a user from a channel, same syntax as INVITE."> <helpop key="tban" value="/TBAN <channel> <duration> <banmask> Sets a timed ban. The duration of the ban can be specified in the -following format: 1w2d3h4m6s which indicates a ban of one week, two -days, three hours, four minutes and six seconds. Alternatively the -ban may just be specified as a number of seconds. All timed bans -appear in the banlist as normal bans and may be safely removed -before their time is up."> +form of 1y2w3d4h5m6s - meaning one year, two weeks, three days, +four hours, five minutes and six seconds. All fields in this +format are optional. Alternatively, the ban may just be specified +as a number of seconds. All timed bans appear in the banlist as +normal bans and may be safely removed before their time is up."> -<helpop key="dccallow" value="/DCCALLOW - List allowed nicks +<helpop key="dccallow" value="/DCCALLOW [(+|-)<nick> [<time>]]|[LIST|HELP] + +/DCCALLOW - List allowed nicks /DCCALLOW LIST - This also lists allowed nicks /DCCALLOW +<nick> [<duration>] - Add a nick /DCCALLOW -<nick> - Remove a nick /DCCALLOW HELP - Display help Duration is optional, and may be specified in seconds or in the -form of 1m2h3d4w5y."> +form of 1y2w3d4h5m6s - meaning one year, two weeks, three days, +four hours, five minutes and six seconds. All fields in this +format are optional."> + +<helpop key="accept" value="/ACCEPT *|(+|-)<nick>[,(+|-)<nick>]+ + +Manages your accept list. This list is used to determine who can +private message you when you have usermode +g set. -<helpop key="accept" value="/ACCEPT * - List accepted nicks +/ACCEPT * - List accepted nicks /ACCEPT +<nick> - Add a nick /ACCEPT -<nick> - Remove a nick -This command accepts multiple nicks like so: -/ACCEPT +<nick1>,+<nick2>,-<nick3> -Manages your accept list. This list is used to determine who can -private message you when you have usermode +g set."> +This command accepts multiple nicks like so: +/ACCEPT +<nick>,-<nick>,+<nick>"> -<helpop key="cycle" value="/CYCLE <channel> :[<reason>] +<helpop key="cycle" value="/CYCLE <channel> [:<reason>] Cycles a channel (leaving and rejoining), overrides restrictions that would stop a new user joining, such as user limits and channel keys."> -<helpop key="title" value="/TITLE <name> <password> +<helpop key="title" value="/TITLE <username> <password> Authenticate for a WHOIS title line and optionally a vhost using the specified username and password."> -<helpop key="watch" value="/WATCH - List watched nicks that are online -/WATCH L - List watched nicks, online and offline -/WATCH C - Clear all watched nicks -/WATCH S - Show statistics +<helpop key="watch" value="/WATCH C|L|l|S|(+|-)<nick> [(+|-)<nick>]+ + +/WATCH - List watched nicks that are online +/WATCH l - List watched nicks that are online +/WATCH L - List watched nicks, online and offline +/WATCH C - Clear all watched nicks +/WATCH S - Show statistics /WATCH +<nick> - Add a nick /WATCH -<nick> - Remove a nick + This command accepts multiple nicks like so: -/WATCH +<nick1> +<nick2> -<nick3>"> +/WATCH +<nick> -<nick> +<nick>"> + +<helpop key="monitor" value="/MONITOR C|L|S|(+|-) <nick>[,<nick>]+ + +/MONITOR L - List all monitored nicks, not differentiating between + online and offline nicks +/MONITOR C - Clear all monitored nicks +/MONITOR S - List all monitored nicks, indicating which are online + and which are offline +/MONITOR + <nick> - Add a nick +/MONITOR - <nick> - Remove a nick + +This command accepts multiple nicks like so: +/MONITOR + <nick>,<nick>,<nick> +/MONITOR - <nick>,<nick>,<nick>"> <helpop key="vhost" value="/VHOST <username> <password> Authenticate for a vhost using the specified username and password."> -<helpop key="remove" value="/REMOVE <channel> <nick> [<reason>] +<helpop key="remove" value="/REMOVE <channel> <nick> [:<reason>] Removes a user from a channel you specify. You must be at least a channel halfoperator to remove a user. A removed user will part with a message stating they were removed from the channel and by whom."> -<helpop key="rmode" value="/RMODE [channel] [modeletter] {[pattern]} +<helpop key="rmode" value="/RMODE <channel> <mode> [<pattern>] -Removes listmodes from a channel. -E.g. /RMODE #Chan b m:* will remove all mute extbans."> +Removes listmodes from a channel, optionally matching a glob-based pattern. +E.g. '/RMODE #channel b m:*' will remove all mute extbans on the channel."> -<helpop key="fpart" value="/FPART <channel> <nick> [<reason>] +<helpop key="fpart" value="/FPART <channel> <nick> [:<reason>] This behaves identically to /REMOVE. /REMOVE is a built-in mIRC command which caused trouble for some users."> -<helpop key="silence" value="/SILENCE - Shows a list of silenced masks +<helpop key="silence" value="/SILENCE [(+|-)<mask> [p|c|i|n|t|a|x]] + +A server-side ignore of the given n!u@h mask. The flags at the end +are optional, and specify what is to be ignored from this mask. + +/SILENCE - Shows a list of silenced masks /SILENCE +<mask> [<flags>] - Add a mask /SILENCE -<mask> - Remove a mask -A serverside ignore of the given n!u@h mask. The letter(s) at the end -specify what is to be ignored from this hostmask. - Valid SILENCE Flags ------------------- @@ -138,18 +165,21 @@ Valid SILENCE Flags a Block all of the above x Exception -Multiple letters may be specified. For an exception, you must pair x +Multiple flags may be specified. For an exception, you must pair x with what you want excepted. For example, if you wanted to except everything from people with a host matching *.foo.net, you would do /SILENCE +*!*@*.foo.net xa +If no flags are specified, it will default to blocking private messages +and private notices (pn). + /SILENCE without a parameter will list the masks that you have silenced."> -<helpop key="knock" value="/KNOCK <channel> +<helpop key="knock" value="/KNOCK <channel> :<reason> Sends a notice to a channel indicating you wish to join."> -<helpop key="user" value="/USER <ident> <local host> <remote host> :<real name> +<helpop key="user" value="/USER <username> <unused> <unused> :<realname> This command is used by your client to register your IRC session, providing your ident and real name to the @@ -157,57 +187,59 @@ server. You should not use it during an established connection."> -<helpop key="nick" value="/NICK <new nick> +<helpop key="nick" value="/NICK <newnick> -Change your nickname to <new nick>."> +Change your nickname to <newnick>."> -<helpop key="quit" value="/QUIT [<reason>] +<helpop key="quit" value="/QUIT [:<message>] Quit from IRC and end your current session."> -<helpop key="version" value="/VERSION +<helpop key="version" value="/VERSION [<servername>] Returns the server's version information."> -<helpop key="ping" value="/PING <server> +<helpop key="ping" value="/PING <servername> [:<servername>] Ping a server. The server will answer with a PONG."> -<helpop key="pong" value="/PONG <server> +<helpop key="pong" value="/PONG <servername> Your client should send this to answer server PINGs. You should not issue this command manually."> -<helpop key="admin" value="/ADMIN [<server>] +<helpop key="admin" value="/ADMIN [<servername>] Shows the administrative information for the given server."> -<helpop key="privmsg" value="/PRIVMSG <target> <text> +<helpop key="privmsg" value="/PRIVMSG <target>[,<target>]+ :<message> Sends a message to a user or channel specified in <target>."> -<helpop key="notice" value="/NOTICE <target> <text> +<helpop key="notice" value="/NOTICE <target>[,<target>]+ :<message> Sends a notice to a user or channel specified in <target>."> -<helpop key="join" value="/JOIN <channel>[,<channel>] [<key>][,<key>] +<helpop key="join" value="/JOIN <channel>[,<channel>]+ [<key>[,<key>]+] Joins one or more channels you provide the names for."> -<helpop key="names" value="/NAMES <channel>[,<channel>] +<helpop key="names" value="/NAMES <channel>[,<channel>]+ -Return a list of users on the channels you provide."> +Return a list of users on the channel(s) you provide."> -<helpop key="part" value="/PART <channel>[,<channel>] [<reason>] +<helpop key="part" value="/PART <channel>[,<channel>]+ [:<reason>] Leaves one or more channels you specify."> -<helpop key="kick" value="/KICK <channel> <nick>[,<nick>] [<reason>] +<helpop key="kick" value="/KICK <channel> <nick>[,<nick>]+ [:<reason>] Kicks a user from a channel you specify. You must be at least a channel halfoperator to kick a user."> -<helpop key="mode" value="/MODE <target> (+|-)<modes> [<mode parameters>] - Change modes of <target>. +<helpop key="mode" value="/MODE <target> [[(+|-)]<modes> [<mode-parameters>]] + +Change or view modes of <target>. /MODE <target> - Show modes of <target>. @@ -221,7 +253,7 @@ channels where they are at least a halfoperator. For a list of all user and channel modes, enter /HELPOP UMODES or /HELPOP CHMODES."> -<helpop key="topic" value="/TOPIC <channel> [<topic>] +<helpop key="topic" value="/TOPIC <channel> [:<topic>] Sets or retrieves the channel topic. If a channel topic is given in the command and either the channel is not +t, or @@ -307,13 +339,13 @@ Valid WHO Fields "> -<helpop key="motd" value="/MOTD [<server>] +<helpop key="motd" value="/MOTD [<servername>] Show the message of the day for <server>. Messages of the day often contain important server rules and notices and should be read prior to using a server."> -<helpop key="oper" value="/OPER <login> <password> +<helpop key="oper" value="/OPER <username> <password> Attempts to authenticate a user as an IRC operator. @@ -329,22 +361,22 @@ Creates a list of all existing channels matching the glob pattern Shows a count of local and remote users, servers and channels."> -<helpop key="userhost" value="/USERHOST <nick> [<nick>] +<helpop key="userhost" value="/USERHOST <nick> [<nick>]+ Returns the hostname and nickname of a user, and some other miscellaneous information."> -<helpop key="away" value="/AWAY [<message>] +<helpop key="away" value="/AWAY [:<message>] If a message is given, marks you as being away, otherwise removes your away status and previous message."> -<helpop key="ison" value="/ISON <nick> [<nick> ...] +<helpop key="ison" value="/ISON <nick> [<nick>]+ Returns a subset of the nicks you give, showing only those that are currently online."> -<helpop key="invite" value="/INVITE <nick> <channel> [<time>] +<helpop key="invite" value="/INVITE [<nick> <channel> [<time>]] Invites a user to a channel. If the channel is NOT +A, only channel halfoperators or above can invite people. If +A is set, @@ -356,7 +388,14 @@ Invited users may override bans, +k, and similar in addition to +i, depending on configuration. If a time is provided, the invite expires after that time and the user -can no longer use it to enter the channel."> +can no longer use it to enter the channel. The time can be specified +in the form of 1y2w3d4h5m6s - meaning one year, two weeks, three days, +four hours, five minutes and six seconds. All fields in this format +are optional. Alternatively, the time may just be specified as a number +of seconds. + +/INVITE without a parameter will list pending invitations for channels +you have been invited to."> <helpop key="pass" value="/PASS <password> @@ -373,7 +412,7 @@ the time they were last seen and their server."> <helpop key="links" value="/LINKS -Shows all servers linked to this one."> +Shows all linked servers."> <helpop key="map" value="/MAP @@ -381,26 +420,26 @@ Shows a graphical representation of all users and servers on the network, and the links between them, as a tree from the perspective of your server."> -<helpop key="whois" value="/WHOIS <nick> [<server>] +<helpop key="whois" value="/WHOIS [<servername>] <nick>[,<nick>]+ Returns the WHOIS information of a user, their channels, hostname, -etc. If a second nickname or server is provided, then a whois is -performed from the server where the user is actually located rather -than locally, showing idle and signon times."> +etc. If a servername is provided, then a whois is performed from +the server where the user is actually located rather than locally, +showing idle and signon times."> -<helpop key="time" value="/TIME [<server>] +<helpop key="time" value="/TIME [<servername>] Returns the local time of the server, or remote time of another server."> -<helpop key="info" value="/INFO [<server>] +<helpop key="info" value="/INFO [<servername>] Returns information on the developers and supporters who made this IRC server possible."> -<helpop key="setname" value="/SETNAME <name> +<helpop key="setname" value="/SETNAME :<realname> -Sets your name to the specified name."> +Sets your real name to the specified real name."> <helpop key="coper" value="Oper Commands @@ -418,18 +457,18 @@ SATOPIC SETHOST SETIDENT SETIDLE SHUN SQUIT SWHOIS TLINE UNLOADMODULE UNLOCKSERV USERIP WALLOPS ZLINE"> -<helpop key="userip" value="/USERIP <nick> [<nick>] +<helpop key="userip" value="/USERIP <nick> [<nick>]+ -Returns the ip and nickname of the given users."> +Returns the IP address and nickname of the given user(s)."> <helpop key="tline" value="/TLINE <mask> This command returns the number of local and global clients matched, and the percentage of clients matched, plus how they were matched (by IP address or by hostname). Mask should be given as either a -nick!user@host or user@IP (wildcards acceptable)."> +nick!user@host or user@IP (wildcards accepted)."> -<helpop key="lockserv" value="/LOCKSERV :[<message>] +<helpop key="lockserv" value="/LOCKSERV [:<message>] Locks out all new connections notifying connecting users that the service is temporarily closed and to try again later."> @@ -438,15 +477,15 @@ service is temporarily closed and to try again later."> Opens the server up again for new connections."> -<helpop key="filter" value="/FILTER <filter-definition> [<action> <flags> [<duration>] :<reason>] +<helpop key="filter" value="/FILTER <pattern> [<action> <flags> [<duration>] :<reason>] -This command will add a filter when more than one parameter is given, -for messages of the types specified by the flags, with the given -filter definition, action, duration (when the action is 'gline', -'zline' or 'shun'), and reason. +This command will add a global filter when more than one parameter is +given, for messages of the types specified by the flags, with the given +filter pattern, action, duration (when the action is 'gline', 'zline' +or 'shun'), and reason. The filter will take effect when a message of any type specified by -the flags and matching the definition is sent to the server, and +the flags and matching the pattern is sent to the server, and perform the specified action. Valid FILTER Actions @@ -501,75 +540,81 @@ channel on official network business."> Retrieves a list of users with more clones than the specified limit."> -<helpop key="check" value="/CHECK <nick|ip|hostmask|channel> [<server>] +<helpop key="check" value="/CHECK <nick>|<ipmask>|<hostmask>|<channel> [<servername>] -Allows opers to look up advanced information on channels, hostmasks -or IP addresses, in a similar way to WHO but in more detail, displaying -most information the IRCD has stored on the target, including all -metadata. +Allows opers to look up advanced information on nicknames, IP addresses, +hostmasks or channels, in a similar way to WHO but in more detail, +displaying most information the server has stored on the target, +including all metadata. With the second parameter given, runs the command remotely on the -specified server."> +specified server, useful especially if used on a nickname that is +online on a remote server."> <helpop key="alltime" value="/ALLTIME -Shows the time on all servers on the network."> +Shows the date and time of all servers on the network."> -<helpop key="rconnect" value="/RCONNECT <source mask> <target mask> +<helpop key="rconnect" value="/RCONNECT <remote-server-mask> <target-server-mask> -The server matching <source mask> will try to connect to the first -server in the config file matching <target mask>."> +The server matching <remote-server-mask> will try to connect to the first +server in the config file matching <target-server-mask>."> -<helpop key="rsquit" value="/RSQUIT <target mask> [<reason>] +<helpop key="rsquit" value="/RSQUIT <target-server-mask> [:<reason>] -Causes a remote server matching <target mask> to be disconnected from +Causes a remote server matching <target-server-mask> to be disconnected from the network."> -<helpop key="globops" value="/GLOBOPS <message> +<helpop key="globops" value="/GLOBOPS :<message> Sends a message to all users with the +g snomask."> -<helpop key="cban" value="/CBAN <channel> [<duration> :[<reason>]] +<helpop key="cban" value="/CBAN <channel> [<duration> [:<reason>]] -Sets or removes a channel ban. You must specify all three parameters +Sets or removes a global channel ban. You must specify all three parameters to add a ban, and one parameter to remove a ban (just the channel). The duration may be specified in seconds, or in the format -1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, -5 minutes and 6 seconds. All fields in this format are optional."> +1y2w3d4h5m6s - meaning one year, two weeks, three days, four hours, +five minutes and six seconds. All fields in this format are optional."> -<helpop key="sajoin" value="/SAJOIN [<nick>] <channel>[,<channel>] +<helpop key="sajoin" value="/SAJOIN [<nick>] <channel>[,<channel>]+ Forces the user to join the channel(s). If no nick is given, it joins the oper doing the /SAJOIN."> -<helpop key="sapart" value="/SAPART <nick> <channel>[,<channel>] +<helpop key="sapart" value="/SAPART <nick> <channel>[,<channel>]+ [:<reason>] -Forces the user to part the channel(s)."> +Forces the user to part the channel(s), with an optional reason."> -<helpop key="samode" value="/SAMODE <target> (+|-)<modes> [<parameters for modes>] +<helpop key="samode" value="/SAMODE <target> (+|-)<modes> [<mode-parameters>] Applies the given mode change to the channel or nick specified."> -<helpop key="sanick" value="/SANICK <nick> <new nick> +<helpop key="sanick" value="/SANICK <nick> <newnick> Changes the user's nick to the new nick."> -<helpop key="sakick" value="/SAKICK <channel> <nick> <reason> +<helpop key="sakick" value="/SAKICK <channel> <nick> [:<reason>] -Kicks the given user from the specified channel."> +Kicks the given user from the specified channel, with an optional reason."> -<helpop key="satopic" value="/SATOPIC <channel> <new topic> +<helpop key="satopic" value="/SATOPIC <channel> :<topic> Applies the given topic to the specified channel."> -<helpop key="saquit" value="/SAQUIT <nick> <reason> +<helpop key="saquit" value="/SAQUIT <nick> :<reason> Forces user to quit with the specified reason."> -<helpop key="setidle" value="/SETIDLE <idle time> +<helpop key="setidle" value="/SETIDLE <duration> -Sets your idle time (in seconds) to the specified value."> +Sets your idle time to the specified value. + +The time can be specified in the form of 1y2w3d4h5m6s - meaning one year, +two weeks, three days, four hours, five minutes and six seconds. +All fields in this format are optional. Alternatively, the time may +just be specified as a number of seconds."> <helpop key="sethost" value="/SETHOST <host> @@ -579,20 +624,24 @@ Sets your host to the specified host."> Sets your ident to the specified ident."> -<helpop key="swhois" line="/SWHOIS <nick> <swhois> +<helpop key="swhois" line="/SWHOIS <nick> :<swhois> + +Sets the user's swhois field to the given swhois message. +This will be visible in their /WHOIS. -Sets the user's swhois field to the given swhois."> +To remove this message again, use: +/SWHOIS <nick> :"> <helpop key="mkpasswd" value="/MKPASSWD <hashtype> <plaintext> Encodes the plaintext to a hash of the given type and displays the result."> -<helpop key="opermotd" value="/OPERMOTD +<helpop key="opermotd" value="/OPERMOTD [<servername>] Displays the Oper MOTD."> -<helpop key="nicklock" value="/NICKLOCK <nick> <new nick> +<helpop key="nicklock" value="/NICKLOCK <nick> <newnick> Changes the user's nick to the new nick, and forces it to remain as such for the remainder of the session."> @@ -601,34 +650,34 @@ it to remain as such for the remainder of the session."> Allows a previously locked user to change nicks again."> -<helpop key="chghost" value="/CHGHOST <nickname> <new hostname> +<helpop key="chghost" value="/CHGHOST <nick> <host> -Changes the hostname of the user to the new hostname."> +Changes the host of the user to the specified host."> -<helpop key="chgname" value="/CHGNAME <nickname> <new name> +<helpop key="chgname" value="/CHGNAME <nick> :<realname> -Changes the name of the user to the new name."> +Changes the real name of the user to the specified real name."> -<helpop key="chgident" value="/CHGIDENT <nickname> <new ident> +<helpop key="chgident" value="/CHGIDENT <nick> <ident> -Changes the ident of the user to the new ident."> +Changes the ident of the user to the specified ident."> -<helpop key="shun" value="/SHUN <nick!user@host> [[<duration>] :<reason>] +<helpop key="shun" value="/SHUN <nick!user@host> [<duration> :<reason>] -Sets or removes a shun (server side ignore) on a host and ident mask. +Sets or removes a shun (global server-side ignore) on a nick!user@host mask. You must specify all three parameters to add a shun, and one parameter -to remove a shun (just the nick!user@host section). +to remove a shun (just the nick!user@host). The duration may be specified in seconds, or in the format -1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, -5 minutes and 6 seconds. All fields in this format are optional."> +1y2w3d4h5m6s - meaning one year, two weeks, three days, four hours, +five minutes and six seconds. All fields in this format are optional."> -<helpop key="die" value="/DIE <server> +<helpop key="die" value="/DIE <servername> This command shuts down the local server. A single parameter is required, which must match the name of the local server."> -<helpop key="restart" value="/RESTART <server> +<helpop key="restart" value="/RESTART <servername> This command restarts the local server. A single parameter is required, which must match the name of the local server."> @@ -637,11 +686,11 @@ required, which must match the name of the local server."> Shows all currently available commands."> -<helpop key="kill" value="/KILL <user> <reason> +<helpop key="kill" value="/KILL <nick>[,<nick>]+ :<reason> This command will disconnect a user from IRC with the given reason."> -<helpop key="rehash" value="/REHASH <mask> +<helpop key="rehash" value="/REHASH [<servermask>] This command will cause the server configuration file to be reread and values reinitialized for all servers matching the server mask, or the @@ -657,105 +706,105 @@ before trying to link them."> Disconnects the server matching the given server mask from this server."> -<helpop key="modules" value="/MODULES +<helpop key="modules" value="/MODULES [<servername>] Lists currently loaded modules, their memory offsets, version numbers, and flags. If you are not an operator, you will see reduced detail."> -<helpop key="loadmodule" value="/LOADMODULE <modname> +<helpop key="loadmodule" value="/LOADMODULE <modulename> Loads the specified module into the local server."> -<helpop key="unloadmodule" value="/UNLOADMODULE <modname> +<helpop key="unloadmodule" value="/UNLOADMODULE <modulename> Unloads a module from the local server."> -<helpop key="reloadmodule" value="/RELOADMODULE <modname> +<helpop key="reloadmodule" value="/RELOADMODULE <modulename> Unloads and reloads a module on the local server."> -<helpop key="gloadmodule" value="/GLOADMODULE <modname> +<helpop key="gloadmodule" value="/GLOADMODULE <modulename> [<servermask>] Loads the specified module on all linked servers."> -<helpop key="gunloadmodule" value="/GUNLOADMODULE <modname> +<helpop key="gunloadmodule" value="/GUNLOADMODULE <modulename> [<servermask>] Unloads a module from all linked servers."> -<helpop key="greloadmodule" value="/GRELOADMODULE <modname> +<helpop key="greloadmodule" value="/GRELOADMODULE <modulename> [<servermask>] Unloads and reloads a module on all linked servers."> <helpop key="kline" value="/KLINE <user@host> [<duration> :<reason>] -Sets or removes a K-line (local host based ban) on a host and ident mask. +Sets or removes a K-line (local user@host based ban) on a user@host mask. You must specify all three parameters to add a ban, and one parameter -to remove a ban (just the user@host section). +to remove a ban (just the user@host). The duration may be specified in seconds, or in the format -1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, -5 minutes and 6 seconds. All fields in this format are optional."> +1y2w3d4h5m6s - meaning one year, two weeks, three days, four hours, +five minutes and six seconds. All fields in this format are optional."> <helpop key="zline" value="/ZLINE <ipmask> [<duration> :<reason>] -Sets or removes a Z-line (ip based ban) on an ip range mask. +Sets or removes a Z-line (global IP based ban) on an IP mask. You must specify all three parameters to add a ban, and one parameter to remove a ban (just the ipmask). The duration may be specified in seconds, or in the format -1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, -5 minutes and 6 seconds. All fields in this format are optional."> +1y2w3d4h5m6s - meaning one year, two weeks, three days, four hours, +five minutes and six seconds. All fields in this format are optional."> <helpop key="qline" value="/QLINE <nickmask> [<duration> :<reason>] -Sets or removes a Q-line (nick based ban) on a nick mask. +Sets or removes a Q-line (global nick based ban) on a nick mask. You must specify all three parameters to add a ban, and one parameter to remove a ban (just the nickmask). The duration may be specified in seconds, or in the format -1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, -5 minutes and 6 seconds. All fields in this format are optional."> +1y2w3d4h5m6s - meaning one year, two weeks, three days, four hours, +five minutes and six seconds. All fields in this format are optional."> <helpop key="gline" value="/GLINE <user@host> [<duration> :<reason>] -Sets or removes a G-line (host based ban) on host mask. +Sets or removes a G-line (global user@host based ban) on a user@host mask. You must specify all three parameters to add a ban, and one -parameter to remove a ban (just the user@host section). +parameter to remove a ban (just the user@host). The duration may be specified in seconds, or in the format -1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, -5 minutes and 6 seconds. All fields in this format are optional."> +1y2w3d4h5m6s - meaning one year, two weeks, three days, four hours, +five minutes and six seconds. All fields in this format are optional."> <helpop key="eline" value="/ELINE <user@host> [<duration> :<reason>] -Sets or removes a E-line (global ban exception) on host mask. +Sets or removes a E-line (global user@host ban exception) on a user@host mask. You must specify at least 3 parameters to add an exception, and one -parameter to remove an exception (just the user@host section). +parameter to remove an exception (just the user@host). The duration may be specified in seconds, or in the format -1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, -5 minutes and 6 seconds. All fields in this format are optional. +1y2w3d4h5m6s - meaning one year, two weeks, three days, four hours, +five minutes and six seconds. All fields in this format are optional. This command has a few important limitations. Bans on *@<ip> can only be negated by an E-line on *@<ip>, bans on *@<host> can be negated by E-lines on *@<ip>, or *@<host>, and bans on <ident>@* or <ident>@<host> can be negated by any E-line that matches."> -<helpop key="wallops" value="/WALLOPS <message> +<helpop key="wallops" value="/WALLOPS :<message> Sends a message to all +w users."> <helpop key="rline" value="/RLINE <regex> [<duration> :<reason>] -Sets or removes an R-line (regex line) on a n!u@h\srealname mask. You +Sets or removes an R-line (global regex ban) on a n!u@h\srealname mask. You must specify all three parameters to add an R-line, and one parameter to remove an R-line (just the regex). The duration may be specified in seconds, or in the format -1y2w3d4h5m6s - meaning one year, two weeks, three days, 4 hours, -5 minutes and 6 seconds. All fields in this format are optional."> +1y2w3d4h5m6s - meaning one year, two weeks, three days, four hours, +five minutes and six seconds. All fields in this format are optional."> -<helpop key="clearchan" value="/CLEARCHAN <channel> [<KILL|KICK|G|Z>] [<reason>] +<helpop key="clearchan" value="/CLEARCHAN <channel> [KILL|KICK|G|Z] [:<reason>] Quits or kicks all non-opers from a channel, optionally G/Z-lines them. Useful for quickly nuking bot channels. @@ -765,7 +814,7 @@ while methods G and Z also add G/Z-lines for all the targets. When used, the victims won't see each other getting kicked or quitting."> -<helpop key="modenotice" value="/MODENOTICE <modeletters> <message> +<helpop key="modenotice" value="/MODENOTICE <modeletters> :<message> Sends a notice to all users who have the given mode(s) set. If multiple mode letters are given, the notice is only sent to users @@ -785,7 +834,7 @@ using their cloak when they quit."> commonchans module). d Deaf mode. User will not receive any messages or notices from channels they are in (requires the deaf module). - g In combination with /ACCEPT, provides for server side + g In combination with /ACCEPT, provides for server-side ignore (requires the callerid module). h Marks as 'available for help' in WHOIS (IRCop only, requires the helpop module). @@ -810,8 +859,8 @@ using their cloak when they quit."> hideoper module). I Hides a user's entire channel list in WHOIS from non-IRCops (requires the hidechans module). - L Stops redirections done by m_redirect (mode must be - enabled in the config). + L Stops redirections done by the redirect module (requires + the redirect module). R Blocks private messages from unregistered users (requires the services account module). S Strips formatting codes out of private messages @@ -879,7 +928,8 @@ using their cloak when they quit."> For example, +w o:R:Brain will op anyone identified to the account 'Brain' on join. (requires the autoop module) - z Blocks non-SSL clients from joining the channel. + z Blocks non-SSL clients from joining the channel + (requires the sslmodes module). A Allows anyone to invite users to the channel (normally only chanops can invite, requires @@ -891,7 +941,8 @@ using their cloak when they quit."> noctcp module). D Delays join messages from users until they message the channel (requires the delayjoin module). - E [~*][lines]:[sec]{[:difference]}{[:backlog]} Allows blocking of similar messages. + E [~|*]<lines>:<sec>[:<difference>][:<backlog>] Allows blocking of + similar messages (requires the repeat module). Kicks as default, blocks with ~ and bans with * The last two parameters are optional. F <changes>:<sec> Blocks nick changes when they equal or exceed the @@ -905,7 +956,8 @@ using their cloak when they quit."> J <seconds> Prevents rejoin after kick for the specified number of seconds. This prevents auto-rejoin (requires the kicknorejoin module). - K Blocks /KNOCK on the channel. + K Blocks /KNOCK on the channel (requires the + knock module). L <channel> If the channel reaches its limit set by +l, redirect users to <channel> (requires the redirect module). @@ -919,8 +971,8 @@ using their cloak when they quit."> topic, modes, and such will not be lost when it empties (can only be set by IRCops, requires the permchannels module). - Q Only ulined servers and their users can kick - (requires the nokicks module) + Q Only U-lined servers and their users can kick + (requires the nokicks module). R Blocks unregistered users from joining (requires the services account module). S Strips formatting codes from messages to the @@ -955,23 +1007,23 @@ being loaded by a server/network administrator. The actual modes available on your network may be very different to this list. Please consult your help channel if you have any questions."> -<helpop key="stats" value="/STATS <symbol> +<helpop key="stats" value="/STATS <symbol> [<servername>] Shows various server statistics. Depending on configuration, some symbols may be only available to opers. Valid symbols are: -e Show E-lines (local ban exemptions) -g Show G-lines (host bans) -k Show K-lines (local host bans) -q Show Q-lines (nick mask bans) -R Show R-lines (regular expression bans) -Z Show Z-lines (IP mask bans) +e Show E-lines (global user@host ban exceptions) +g Show G-lines (global user@host bans) +k Show K-lines (local user@host bans) +q Show Q-lines (global nick bans) +R Show R-lines (global regular expression bans) +Z Show Z-lines (global IP mask bans) -s Show filters -C Show channel bans -H Show shuns +s Show filters (global) +C Show channel bans (global) +H Show shuns (global) c Show link blocks d Show configured DNSBLs and related statistics @@ -1011,8 +1063,8 @@ Note that all /STATS use is broadcast to online IRC operators."> K Allows receipt of remote kill messages. l Allows receipt of local linking related messages. L Allows receipt of remote linking related messages. - n See local nickname changes (requires the seenicks module). - N See remote nickname changes (requires the seenicks modules). + n Allows receipt of local nickname changes (requires the seenicks module). + N Allows receipt of remote nickname changes (requires the seenicks modules). o Allows receipt of oper-up, oper-down, and oper-failure messages. O Allows receipt of remote oper-up, oper-down, and oper-failure messages. q Allows receipt of local quit messages. diff --git a/docs/conf/inspircd.conf.example b/docs/conf/inspircd.conf.example index 013cb920c..a5aafe0d1 100644 --- a/docs/conf/inspircd.conf.example +++ b/docs/conf/inspircd.conf.example @@ -207,7 +207,7 @@ # -- It is important to note that connect tags are read from the -- # # TOP DOWN. This means that you should have more specific deny # # and allow tags at the top, progressively more general, followed # -# by a <connect allow="*" (should you wish to have one). # +# by a <connect allow="*"> (should you wish to have one). # # # # Connect blocks are searched twice for each user - once when the TCP # # connection is accepted, and once when the user completes their # @@ -246,7 +246,7 @@ # # You may also use any of the above other than bcrypt prefixed with # either "hmac-" or "pbkdf2-hmac-" (requires the pbkdf2 module). - # Create hashed passwords with: /mkpasswd <hash> <password> + # Create hashed passwords with: /MKPASSWD <hashtype> <plaintext> #hash="bcrypt" # password: Password to use for this block/user(s) @@ -259,7 +259,7 @@ # timeout: How long the server will wait before disconnecting # a user if they do not do anything on connect. # (Note, this is a client-side thing, if the client does not - # send /nick, /user or /pass) + # send /NICK, /USER or /PASS) timeout="10" # localmax: Maximum local connections per IP (or CIDR mask, see below). @@ -291,8 +291,8 @@ # modes: Usermodes that are set on users in this block on connect. # Enabling this option requires that the conn_umodes module be loaded. - # This entry is highly recommended to use for/with IP Cloaking/masking. - # For the example to work, this also requires that the "cloaking" + # This entry is highly recommended to use for/with IP cloaking/masking. + # For the example to work, this also requires that the cloaking # module be loaded as well. modes="+x" @@ -343,7 +343,7 @@ # timeout: How long the server will wait before disconnecting # a user if they do not do anything on connect. # (Note, this is a client-side thing, if the client does not - # send /nick, /user or /pass) + # send /NICK, /USER or /PASS) timeout="10" # pingfreq: How often the server tries to ping connecting clients. @@ -405,7 +405,7 @@ # modes: Usermodes that are set on users in this block on connect. # Enabling this option requires that the conn_umodes module be loaded. - # This entry is highly recommended to use for/with IP Cloaking/masking. + # This entry is highly recommended to use for/with IP cloaking/masking. # For the example to work, this also requires that the cloaking # module be loaded as well. modes="+x"> @@ -624,7 +624,7 @@ # See m_exemptchanops in modules.conf.example for more details. exemptchanops="censor:o filter:o nickflood:o nonick:v regmoderated:o" - # invitebypassmodes: This allows /invite to bypass other channel modes. + # invitebypassmodes: This allows /INVITE to bypass other channel modes. # (Such as +k, +j, +l, etc.) invitebypassmodes="yes" @@ -687,10 +687,10 @@ announceinvites="dynamic" # hideulines: If this value is set to yes, U-lined servers will - # be hidden from non-opers in /links and /map. + # be hidden from non-opers in /LINKS and /MAP. hideulines="no" - # flatlinks: If this value is set to yes, /map and /links will + # flatlinks: If this value is set to yes, /MAP and /LINKS will # be flattened when shown to non-opers. flatlinks="no" @@ -707,7 +707,7 @@ # from the server. hidebans="no" - # hidekills: If defined, replaces who set a /kill with a custom string. + # hidekills: If defined, replaces who executed a /KILL with a custom string. hidekills="" # hideulinekills: Hide kills from clients of ulined servers from server notices. @@ -719,7 +719,7 @@ hidesplits="no" # maxtargets: Maximum number of targets per command. - # (Commands like /notice, /privmsg, /kick, etc) + # (Commands like /NOTICE, /PRIVMSG, /KICK, etc) maxtargets="20" # customversion: A custom message to be displayed in the comments field @@ -750,7 +750,7 @@ # affects the display in WHOIS. genericoper="no" - # userstats: /stats commands that users can run (opers can run all). + # userstats: /STATS commands that users can run (opers can run all). userstats="Pu"> #-#-#-#-#-#-#-#-#-#-#-#-# LIMITS CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-# @@ -818,7 +818,7 @@ # # An example log tag would be: # <log method="file" type="OPER" level="default" target="opers.log"> -# which would log all information on /oper (failed and successful) to +# which would log all information on /OPER (failed and successful) to # a file called opers.log. # # There are many different types which may be used, and modules may @@ -862,17 +862,17 @@ #-#-#-#-#-#-#-#-#-#-#-#-#- WHOWAS OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-# # # -# This tag lets you define the behaviour of the /whowas command of # +# This tag lets you define the behaviour of the /WHOWAS command of # # your server. # # # <whowas # groupsize: Maximum entries per nick shown when performing - # a /whowas nick. + # a /WHOWAS <nick>. groupsize="10" # maxgroups: Maximum number of nickgroups that can be added to - # the list so that /whowas does not use a lot of resources on + # the list so that /WHOWAS does not use a lot of resources on # large networks. maxgroups="100000" @@ -900,7 +900,7 @@ # nick: Nick to disallow. Wildcards are supported. nick="ChanServ" - # reason: Reason to display on /nick. + # reason: Reason to display on /NICK. reason="Reserved for a network service"> <badhost @@ -920,7 +920,7 @@ # Wildcards and CIDR (if you specify an IP) can be used. host="*@ircop.example.com" - # reason: Reason for exception. Only shown in /stats e + # reason: Reason for exception. Only shown in /STATS e. reason="Oper's hostname"> #-#-#-#-#-#-#-#-#-#-#- INSANE BAN OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-#-# diff --git a/docs/conf/links.conf.example b/docs/conf/links.conf.example index ad2efa9f7..735cac304 100644 --- a/docs/conf/links.conf.example +++ b/docs/conf/links.conf.example @@ -64,19 +64,19 @@ # servers will not be shown when users do a /MAP or /LINKS. hidden="no" - # passwords: the passwords we send and receive. + # passwords: The passwords we send and receive. # The remote server will have these passwords reversed. # Passwords that contain a space character or begin with # a colon (:) are invalid and may not be used. sendpass="outgoing!password" recvpass="incoming!password"> -# A duplicate of the first link block without comments +# A duplicate of the first link block without comments, # if you like copying & pasting. <link name="hub.example.org" ipaddr="penguin.example.org" port="7000" - allowmask="203.0.113.0/24" + allowmask="203.0.113.0/24 127.0.0.0/8 2001:db8::/32" timeout="5m" ssl="gnutls" bind="1.2.3.4" @@ -94,7 +94,7 @@ sendpass="penguins" recvpass="polarbears"> -# Simple autoconnect block. This enables automatic connection of a server +# Simple autoconnect block. This enables automatic connections to a server. # Recommended setup is to have leaves connect to the hub, and have no # automatic connections started by the hub. <autoconnect period="10m" server="hub.example.org"> @@ -108,15 +108,15 @@ server="hub.us.example.org hub.eu.example.org leaf.eu.example.org"> -#-#-#-#-#-#-#-#-#-#-#-#- ULINES CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-# -# This tag defines a ulined server. A U-Lined server has special # -# permissions, and should be used with caution. Services servers are # -# usually u-lined in this manner. # -# # -# The 'silent' value, if set to yes, indicates that this server should# -# not generate quit and connect notices, which can cut down on noise # -# to opers on the network. # -# # +#-#-#-#-#-#-#-#-#-#-#-#-# U-LINES CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-#-# +# This tag defines a U-lined server. A U-lined server has special # +# permissions, and should be used with caution. Services servers are # +# usually U-lined in this manner. # +# # +# The 'silent' value, if set to yes, indicates that this server should # +# not generate quit and connect notices, which can cut down on noise # +# to opers on the network. # +# # <uline server="services.example.com" silent="yes"> # Once you have edited this file you can remove this line. This is just to diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 3b0b46a84..bbb8e2d13 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -79,7 +79,7 @@ # read from the top of the file to the bottom. # # # # usercommand - If this is true, the alias can be run simply as # -# /aliasname. Defaults to true. # +# /ALIASNAME. Defaults to true. # # # # channelcommand - If this is true, the alias can be used as an # # in-channel alias or 'fantasy command', prefixed # @@ -313,7 +313,7 @@ # The webirc method is the recommended way to allow gateways to forward # IP/host information. When using this method the gateway sends a WEBIRC # message to the server on connection. For more details please read the -# IRCv3 WebIRC specification at http://ircv3.net/specs/extensions/webirc.html. +# IRCv3 WebIRC specification at: https://ircv3.net/specs/extensions/webirc.html # # When using this method you must specify a wildcard mask or CIDR range # to allow gateway connections from and at least one of either a SSL @@ -751,11 +751,11 @@ # # # chanmodes - One or more channel modes that can not be added/removed # # by users. You can exempt server operators from this # -# with the servers/use-disabled-commands privilege. # +# with the servers/use-disabled-modes privilege. # # # # usermodes - One or more user modes that can not be added/removed by # # users. You can exempt server operators from this with # -# the servers/use-disabled-commands privilege. # +# the servers/use-disabled-modes privilege. # # # # fakenonexistent - Whether to pretend that a disabled command/mode # # does not exist when executed/changed by a user. # @@ -774,7 +774,7 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # DNS blacklist module: Provides support for looking up IPs on one or # # more blacklists. # -#<module name="dnsbl"> # +#<module name="dnsbl"> # # # For configuration options please see the wiki page for dnsbl at # # https://wiki.inspircd.org/Modules/3.0/dnsbl # @@ -787,8 +787,8 @@ # nonick, nonotice, regmoderated, stripcolor, and topiclock. # # See <options:exemptchanops> in inspircd.conf.example for a more # # detailed list of the restriction modes that can be exempted. # -# These are settable using /mode #chan +X <restriction>:<status> # -#<module name="exemptchanops"> # +# These are settable using: /MODE #chan +X <restriction>:<status> # +#<module name="exemptchanops"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Filter module: Provides message filtering, similar to SPAMFILTER. # @@ -820,7 +820,7 @@ # # # Optional - If you specify to use the filter module, then # # specify below the path to the filter.conf file, or define some # -# <filter> tags. # +# <keyword> tags. # # # #<include file="examples/filter.conf.example"> @@ -847,7 +847,7 @@ # <connect deny="*" geoip="TR,RU"> # # If enabled you can also ban people from channnels by country code -# using the G: extban (e.g. /mode #channel +b G:US). +# using the G: extban (e.g. /MODE #channel +b G:US). # <geoip extban="yes"> # # The country code must be in capitals and should be an ISO country @@ -1041,7 +1041,7 @@ # # Further information on these extensions can be found at the IRCv3 # working group website: -# http://ircv3.net/irc/ +# https://ircv3.net/irc/ # #<module name="ircv3"> # The following block can be used to control which extensions are @@ -1074,6 +1074,12 @@ #<module name="ircv3_chghost"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# IRCv3 client-to-client tags module: Provides the message-tags IRCv3 +#Â extension which allows clients to add extra data to their messages. +# This is used to support new IRCv3 features such as replies and ids. +#<module name="ircv3_ctctags"> + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # IRCv3 echo-message module: Provides the echo-message IRCv3 # extension which allows capable clients to get an acknowledgement when # their messages are delivered and learn what modifications, if any, @@ -1247,7 +1253,7 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Map hiding module: replaces /MAP and /LINKS output to users with a # -# message to see a website, set by maphide="http://test.org/map" in # +# message to see a website, set by maphide="https://test.org/map" in # # the <security> tag, instead. # #<module name="maphide"> @@ -1293,7 +1299,7 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Named modes module: Allows for the display and set/unset of channel # modes via long-form mode names via +Z and the /PROP command. -# For example, to set a ban, do /mode #channel +Z ban=foo!bar@baz or +# For example, to set a ban, do /MODE #channel +Z ban=foo!bar@baz or # /PROP #channel ban=foo!bar@baz #<module name="namedmodes"> @@ -1376,7 +1382,7 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Oper channels mode: Adds the +O channel mode and extban O:<mask> # to ban, except, etc. specific oper types. For example -# /mode #channel +iI O:* is equivalent to channel mode +O, but you +# /MODE #channel +iI O:* is equivalent to channel mode +O, but you # may also set +iI O:AdminTypeOnly to only allow admins. # Modes +I and +e work in a similar fashion. #<module name="operchans"> @@ -1639,7 +1645,8 @@ #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Remove module: Adds the /REMOVE command which is a peaceful -# alternative to /KICK. +# alternative to /KICK. It also provides the /FPART command which works +# in the same way as /REMOVE. #<module name="remove"> # # supportnokicks: If true, /REMOVE is not allowed on channels where the @@ -1649,27 +1656,36 @@ #<remove supportnokicks="true" protectedrank="50000"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -# A module to block, kick or ban upon similar messages being uttered several times. -# Syntax [~*][lines]:[sec]{[:difference]}{[:matchlines]} -# ~ is to block, * is to ban, default is kick. -# lines - In mode 1 the amount of lines that has to match consecutively - In mode 2 the size of the backlog to keep for matching -# seconds - How old the message has to be before it's invalidated. -# distance - Edit distance, in percent, between two strings to trigger on. -# matchlines - When set, the function goes into mode 2. In this mode the function will trigger if this many of the last <lines> matches. +# Repeat module: Allows to block, kick or ban upon similar messages +# being uttered several times. Provides channel mode +E. +# +# Syntax: [~|*]<lines>:<sec>[:<difference>][:<backlog>] +# ~ is to block, * is to ban, default is kick. +# lines - In mode 1, the amount of lines that has to match consecutively. +# In mode 2, the size of the backlog to keep for matching. +# seconds - How old the message has to be before it's invalidated. +# difference - Edit distance, in percent, between two strings to trigger on. +# backlog - When set, the function goes into mode 2. In this mode the +# function will trigger if this many of the last <lines> matches. # # As this module can be rather CPU-intensive, it comes with some options. -# maxbacklog - Maximum size that can be specified for backlog. 0 disables multiline matching. -# maxdistance - Max percentage of difference between two lines we'll allow to match. Set to 0 to disable edit-distance matching. -# maxlines - Max lines of backlog to match against. -# maxtime - Maximum period of time a user can set. 0 to allow any. -# size - Maximum number of characters to check for, can be used to truncate messages -# before they are checked, resulting in less CPU usage. Increasing this beyond 512 -# doesn't have any effect, as the maximum length of a message on IRC cannot exceed that. -#<repeat maxbacklog="20" maxlines="20" maxdistance="50" maxtime="0" size="512"> +# maxbacklog - Maximum size that can be specified for backlog. 0 disables +# multiline matching. +# maxdistance - Max percentage of difference between two lines we'll allow +# to match. Set to 0 to disable edit-distance matching. +# maxlines - Max lines of backlog to match against. +# maxtime - Maximum period of time a user can set. 0 to allow any. +# size - Maximum number of characters to check for, can be used to +# truncate messages before they are checked, resulting in +# less CPU usage. Increasing this beyond 512 doesn't have +# any effect, as the maximum length of a message on IRC +# cannot exceed that. +#<repeat maxbacklog="20" maxdistance="50 maxlines="20" maxtime="0" size="512"> #<module name="repeat"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -# Restricted channels module: Allows only opers or registered users to +# Restricted channels module: Allows only opers with the +# channels/restricted-create priv and/or registered users to # create channels. # # You probably *DO NOT* want to load this module on a public network. @@ -1715,10 +1731,11 @@ # so that at least \s or [[:space:]] is available. #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# -# RMODE module: Adds the /RMODE command -# Allows channel mods to remove list modes en masse. -# Syntax: /rmode <channel> <mode> [pattern] -# E.g. '/rmode #Channel b m:*' will remove all mute-extbans on the channel. +# RMODE module: Adds the /RMODE command. +# Allows channel operators to remove list modes en masse, optionally +# matching a glob-based pattern. +# Syntax: /RMODE <channel> <mode> [<pattern>] +# E.g. '/RMODE #channel b m:*' will remove all mute extbans on the channel. #<module name="rmode"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# @@ -1861,8 +1878,8 @@ # changes their real name. Defaults to to yes if # # oper-only and no if usable by everyone. # # # -#<setname notifyopers="yes" # -# operonly="no"> # +#<setname notifyopers="yes" +# operonly="no"> #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Serverban: Implements extended ban 's', which stops anyone connected @@ -1879,7 +1896,7 @@ # they enter a command. # # This module adds one command for each <showfile> tag that shows the # # given file to the user as a series of messages or numerics. # -#<module name="showfile"> # +#<module name="showfile"> # # #-#-#-#-#-#-#-#-#-#-# SHOWFILE CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-#-# # # diff --git a/docs/conf/opers.conf.example b/docs/conf/opers.conf.example index 98bc47c69..f9f6a75d4 100644 --- a/docs/conf/opers.conf.example +++ b/docs/conf/opers.conf.example @@ -1,4 +1,4 @@ -#-#-#-#-#-#-#-#-#-#-#-#- CLASS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#- +#-#-#-#-#-#-#-#-#-#-#-#-# CLASS CONFIGURATION #-#-#-#-#-#-#-#-#-#-#-# # # # Classes are a group of commands which are grouped together and # # given a unique name. They're used to define which commands # @@ -19,19 +19,25 @@ # privs: Special privileges that users with this class may utilise. # VIEWING: - # - channels/auspex: allows opers with this priv to see more detail about channels than normal users. + # - channels/auspex: allows opers with this priv to see more details about channels than normal users. # - users/auspex: allows opers with this priv to view more details about users than normal users, e.g. real host and IP. # - users/channel-spy: allows opers with this priv to view the private/secret channels that a user is on. - # - servers/auspex: allows opers with this priv to see more detail about server information than normal users. + # - servers/auspex: allows opers with this priv to see more details about server information than normal users. # ACTIONS: - # - users/mass-message: allows opers with this priv to PRIVMSG and NOTICE to a server mask (e.g. NOTICE $*) - # - users/samode-usermodes: allows opers with this priv to change the user modes of any other user using /SAMODE + # - users/mass-message: allows opers with this priv to PRIVMSG and NOTICE to a server mask (e.g. NOTICE $*). + # - users/samode-usermodes: allows opers with this priv to change the user modes of any other user using /SAMODE. # PERMISSIONS: - #. - channels/ignore-nonicks: allows opers with this priv to change their nick when on a +N channel. - # - users/flood/no-fakelag: prevents opers from being penalized with fake lag for flooding (*NOTE) - # - users/flood/no-throttle: allows opers with this priv to send commands without being throttled (*NOTE) - # - users/flood/increased-buffers: allows opers with this priv to send and receive data without worrying about being disconnected for exceeding limits (*NOTE) - #. - users/callerid-override: allows opers with this priv to message people using callerid without being on their callerid list. + # - channels/ignore-noctcp: allows opers with this priv to send a CTCP to a +C channel. + # - channels/ignore-nonicks: allows opers with this priv to change their nick when on a +N channel. + # - channels/restricted-create: allows opers with this priv to create channels if the restrictchans module is loaded. + # - users/flood/no-fakelag: prevents opers from being penalized with fake lag for flooding (*NOTE). + # - users/flood/no-throttle: allows opers with this priv to send commands without being throttled (*NOTE). + # - users/flood/increased-buffers: allows opers with this priv to send and receive data without worrying about being disconnected for exceeding limits (*NOTE). + # - users/callerid-override: allows opers with this priv to message people using callerid without being on their callerid list. + # - users/ignore-noctcp: allows opers with this priv to send a CTCP to a +T user. + # - users/sajoin-others: allows opers with this priv to /SAJOIN users other than themselves. + # - servers/use-disabled-commands: allows opers with this priv to use disabled commands. + # - servers/use-disabled-modes: allows opers with this priv to use disabled modes. # # *NOTE: These privs are potentially dangerous, as they grant users with them the ability to hammer your server's CPU/RAM as much as they want, essentially. privs="users/auspex channels/auspex servers/auspex users/mass-message users/flood/no-throttle users/flood/increased-buffers" @@ -57,13 +63,13 @@ # # <type - # name: Name of type. Used in actual server operator accounts below. + # name: Name of the type. Used in actual server operator accounts below. name="NetAdmin" # classes: Classes (blocks above) that this type belongs to. classes="SACommands OperChat BanControl HostCloak Shutdown ServerLink" - # vhost: Host opers of this type get when they log in (oper up). This is optional. + # vhost: Host that opers of this type get when they log in (oper up). This is optional. vhost="netadmin.omega.example.org" # maxchans: Maximum number of channels opers of this type can be in at once. @@ -71,7 +77,7 @@ # modes: User modes besides +o that are set on an oper of this type # when they oper up. Used for snomasks and other things. - # Requires the opermodes module be loaded. + # Requires the opermodes module to be loaded. modes="+s +cCqQ"> <type name="GlobalOp" classes="SACommands OperChat BanControl HostCloak ServerLink" vhost="ircop.omega.example.org"> @@ -84,9 +90,9 @@ # Remember to only make operators out of trustworthy people. # # # -# Operator account with a plain-text password. +# Operator account with a plaintext password. <oper - # name: Oper login that is used to oper up (/oper name password). + # name: Oper login that is used to oper up (/OPER <username> <password>). # Remember: This is case sensitive. name="Attila" @@ -101,7 +107,7 @@ # ** ADVANCED ** This option is disabled by default. # fingerprint: When using the sslinfo module, you may specify - # a key fingerprint here. This can be obtained by using the /sslinfo + # a key fingerprint here. This can be obtained by using the /SSLINFO # command while the module is loaded, and is also noticed on connect. # This enhances security by verifying that the person opering up has # a matching SSL client certificate, which is very difficult to @@ -115,7 +121,7 @@ # that the private key is well-protected! Requires the sslinfo module. #autologin="on" - # sslonly: If on, this oper can only oper up if they're using a SSL connection. + # sslonly: If on, this oper can only oper up if they're using an SSL connection. # Setting this option adds a decent bit of security. Highly recommended # if the oper is on wifi, or specifically, unsecured wifi. Note that it # is redundant to specify this option if you specify a fingerprint. @@ -140,21 +146,21 @@ # Operator with a hashed password. It is highly recommended to use hashed passwords. <oper - # name: Oper login that is used to oper up (/oper name password). + # name: Oper login that is used to oper up (/OPER <username> <password>). # Remember: This is case sensitive. name="Adam" - # hash: the hash function this password is hashed with. Requires the + # hash: The hash function this password is hashed with. Requires the # module for the selected function (bcrypt, md5, sha1, or sha256) and # the password hashing module (password_hash) to be loaded. # # You may also use any of the above other than bcrypt prefixed with # either "hmac-" or "pbkdf2-hmac-" (requires the pbkdf2 module). - # Create hashed passwords with: /mkpasswd <hash> <password> + # Create hashed passwords with: /MKPASSWD <hashtype> <plaintext>. hash="bcrypt" # password: A hash of the password (see above option) hashed - # with /mkpasswd <hash> <password>. See the password_hash module + # with /MKPASSWD <hashtype> <plaintext>. See the password_hash module # in modules.conf for more information about password hashing. password="qQmv3LcF$Qh63wzmtUqWp9OXnLwe7yv1GcBwHpq59k2a0UrY8xe0" diff --git a/docs/conf/services/anope.conf.example b/docs/conf/services/anope.conf.example index 603bb538d..4068871c8 100644 --- a/docs/conf/services/anope.conf.example +++ b/docs/conf/services/anope.conf.example @@ -1,5 +1,5 @@ # This file contains aliases and nickname reservations which are used -# by Anope. See https://www.anope.org/ for more information on Anope. +# by Anope. See https://www.anope.org for more information on Anope. # This file inherits from the generic config to avoid repetition. <include file="examples/services/generic.conf.example"> diff --git a/docs/conf/services/atheme.conf.example b/docs/conf/services/atheme.conf.example index 037087998..ac87399c2 100644 --- a/docs/conf/services/atheme.conf.example +++ b/docs/conf/services/atheme.conf.example @@ -1,5 +1,6 @@ # This file contains aliases and nickname reservations which are used -# by Atheme. See http://atheme.net for more information on Atheme. +# by Atheme. See https://atheme.github.io/atheme.html for more +# information on Atheme. # This file inherits from the generic config to avoid repetition. <include file="examples/services/generic.conf.example"> diff --git a/include/clientprotocol.h b/include/clientprotocol.h index ec033e166..44896a3a3 100644 --- a/include/clientprotocol.h +++ b/include/clientprotocol.h @@ -537,7 +537,7 @@ class ClientProtocol::MessageTagProvider : public Events::ModuleEventListener * The default implementation does nothing. * @param msg Message to be populated with tags. */ - virtual void OnClientProtocolPopulateTags(ClientProtocol::Message& msg) + virtual void OnPopulateTags(ClientProtocol::Message& msg) { } diff --git a/include/event.h b/include/event.h index 0251ec4ac..a042c6a11 100644 --- a/include/event.h +++ b/include/event.h @@ -39,7 +39,7 @@ class Events::ModuleEventProvider : public ServiceProvider, private dynamic_refe bool operator()(ModuleEventListener* one, ModuleEventListener* two) const; }; - typedef insp::flat_multiset<ModuleEventListener*, Comp> SubscriberList; + typedef insp::flat_multiset<ModuleEventListener*, Comp, std::less<ModuleEventListener*> > SubscriberList; /** Constructor * @param mod Module providing the event(s) diff --git a/include/flat_map.h b/include/flat_map.h index bef1404e4..62815168b 100644 --- a/include/flat_map.h +++ b/include/flat_map.h @@ -200,10 +200,10 @@ class flat_map_base } // namespace detail -template <typename T, typename Comp = std::less<T> > -class flat_set : public detail::flat_map_base<T, Comp> +template <typename T, typename Comp = std::less<T>, typename ElementComp = Comp> +class flat_set : public detail::flat_map_base<T, Comp, T, ElementComp> { - typedef detail::flat_map_base<T, Comp> base_t; + typedef detail::flat_map_base<T, Comp, T, ElementComp> base_t; public: typedef typename base_t::iterator iterator; @@ -240,10 +240,10 @@ class flat_set : public detail::flat_map_base<T, Comp> } }; -template <typename T, typename Comp = std::less<T> > -class flat_multiset : public detail::flat_map_base<T, Comp> +template <typename T, typename Comp = std::less<T>, typename ElementComp = Comp> +class flat_multiset : public detail::flat_map_base<T, Comp, T, ElementComp> { - typedef detail::flat_map_base<T, Comp> base_t; + typedef detail::flat_map_base<T, Comp, T, ElementComp> base_t; public: typedef typename base_t::iterator iterator; @@ -280,10 +280,10 @@ class flat_multiset : public detail::flat_map_base<T, Comp> } }; -template <typename T, typename U, typename Comp = std::less<T> > -class flat_map : public detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, Comp> > +template <typename T, typename U, typename Comp = std::less<T>, typename ElementComp = Comp > +class flat_map : public detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, ElementComp> > { - typedef detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, Comp> > base_t; + typedef detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, ElementComp> > base_t; public: typedef typename base_t::iterator iterator; @@ -333,10 +333,10 @@ class flat_map : public detail::flat_map_base<std::pair<T, U>, Comp, T, detail:: } }; -template <typename T, typename U, typename Comp = std::less<T> > -class flat_multimap : public detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, Comp> > +template <typename T, typename U, typename Comp = std::less<T>, typename ElementComp = Comp > +class flat_multimap : public detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, ElementComp> > { - typedef detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, Comp> > base_t; + typedef detail::flat_map_base<std::pair<T, U>, Comp, T, detail::map_pair_compare<std::pair<T, U>, ElementComp> > base_t; public: typedef typename base_t::iterator iterator; diff --git a/include/inspircd.h b/include/inspircd.h index 1cbc3f2c2..dd3195039 100644 --- a/include/inspircd.h +++ b/include/inspircd.h @@ -509,6 +509,12 @@ class CoreExport InspIRCd */ static bool IsValidDuration(const std::string& str); + /** Return a duration in seconds as a human-readable string. + * @param duration The duration in seconds to convert to a human-readable string. + * @return A string representing the given duration. + */ + static std::string DurationString(time_t duration); + /** Attempt to compare a password to a string from the config file. * This will be passed to handling modules which will compare the data * against possible hashed equivalents in the input string. diff --git a/include/iohook.h b/include/iohook.h index 9ca17d77e..85404b09c 100644 --- a/include/iohook.h +++ b/include/iohook.h @@ -49,7 +49,7 @@ class IOHookProvider : public refcountbase, public ServiceProvider */ bool IsMiddle() const { return middlehook; } - /** Called when the provider should hook an incoming connection and act as being on the server side of the connection. + /** Called when the provider should hook an incoming connection and act as being on the server-side of the connection. * This occurs when a bind block has a hook configured and the listener accepts a connection. * @param sock Socket to hook * @param client Client IP address and port diff --git a/include/modules/ctctags.h b/include/modules/ctctags.h new file mode 100644 index 000000000..d8798de54 --- /dev/null +++ b/include/modules/ctctags.h @@ -0,0 +1,135 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#pragma once + +#include "event.h" + +namespace CTCTags +{ + class EventListener; + class TagMessage; + class TagMessageDetails; +} + +class CTCTags::TagMessage : public ClientProtocol::Message +{ + public: + TagMessage(User* source, const Channel* targetchan, const ClientProtocol::TagMap& Tags) + : ClientProtocol::Message("TAGMSG", source) + { + PushParamRef(targetchan->name); + AddTags(Tags); + SetSideEffect(true); + } + + TagMessage(User* source, const User* targetuser, const ClientProtocol::TagMap& Tags) + : ClientProtocol::Message("TAGMSG", source) + { + if (targetuser->registered & REG_NICK) + PushParamRef(targetuser->nick); + else + PushParam("*"); + AddTags(Tags); + SetSideEffect(true); + } + + TagMessage(User* source, const char* targetstr, const ClientProtocol::TagMap& Tags) + : ClientProtocol::Message("TAGMSG", source) + { + PushParam(targetstr); + AddTags(Tags); + SetSideEffect(true); + } +}; + +class CTCTags::TagMessageDetails +{ + public: + /** Whether to echo the tags at all. */ + bool echo; + + /* Whether to send the original tags back to clients with echo-message support. */ + bool echo_original; + + /** The users who are exempted from receiving this message. */ + CUList exemptions; + + /** IRCv3 message tags sent to the server by the user. */ + const ClientProtocol::TagMap tags_in; + + /** IRCv3 message tags sent out to users who get this message. */ + ClientProtocol::TagMap tags_out; + + TagMessageDetails(const ClientProtocol::TagMap& tags) + : echo(true) + , echo_original(false) + , tags_in(tags) + { + } +}; + +class CTCTags::EventListener + : public Events::ModuleEventListener +{ + protected: + EventListener(Module* mod, unsigned int eventprio = DefaultPriority) + : ModuleEventListener(mod, "event/tagmsg", eventprio) + { + } + + public: + /** Called before a user sends a tag message to a channel, a user, or a server glob mask. + * @param user The user sending the message. + * @param target The target of the message. This can either be a channel, a user, or a server + * glob mask. + * @param details Details about the message such as the message tags or whether to echo. See the + * TagMessageDetails class for more information. + * @return MOD_RES_ALLOW to explicitly allow the message, MOD_RES_DENY to explicitly deny the + * message, or MOD_RES_PASSTHRU to let another module handle the event. + */ + virtual ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, TagMessageDetails& details) { return MOD_RES_PASSTHRU; } + + /** Called immediately after a user sends a tag message to a channel, a user, or a server glob mask. + * @param user The user sending the message. + * @param target The target of the message. This can either be a channel, a user, or a server + * glob mask. + * @param details Details about the message such as the message tags or whether to echo. See the + * TagMessageDetails class for more information. + */ + virtual void OnUserPostTagMessage(User* user, const MessageTarget& target, const TagMessageDetails& details) { } + + /** Called immediately before a user sends a tag message to a channel, a user, or a server glob mask. + * @param user The user sending the message. + * @param target The target of the message. This can either be a channel, a user, or a server + * glob mask. + * @param details Details about the message such as the message tags or whether to echo. See the + * TagMessageDetails class for more information. + */ + virtual void OnUserTagMessage(User* user, const MessageTarget& target, const TagMessageDetails& details) { } + + /** Called when a tag message sent by a user to a channel, a user, or a server glob mask is blocked. + * @param user The user sending the message. + * @param target The target of the message. This can either be a channel, a user, or a server + * glob mask. + * @param details Details about the message such as the message tags or whether to echo. See the + * TagMessageDetails class for more information. + */ + virtual void OnUserTagMessageBlocked(User* user, const MessageTarget& target, const TagMessageDetails& details) { } +}; diff --git a/include/modules/ircv3.h b/include/modules/ircv3.h index c6f3e503a..53b1dc2b6 100644 --- a/include/modules/ircv3.h +++ b/include/modules/ircv3.h @@ -75,7 +75,7 @@ class IRCv3::CapTag : public ClientProtocol::MessageTagProvider return cap.get(user); } - void OnClientProtocolPopulateTags(ClientProtocol::Message& msg) override + void OnPopulateTags(ClientProtocol::Message& msg) override { T& tag = static_cast<T&>(*this); const std::string* const val = tag.GetValue(msg); diff --git a/include/modules/who.h b/include/modules/who.h index 4fcbe5f91..983cece46 100644 --- a/include/modules/who.h +++ b/include/modules/who.h @@ -71,6 +71,17 @@ class Who::Request /** A user specified label for the WHOX response. */ std::string whox_querytype; + /** Get the index in the response parameters for the different data fields + * + * The fields 'r' (realname) and 'd' (hops) will always be missing in a non-WHOX + * query, because WHOX splits them to 2 fields, where old WHO has them as one. + * + * @param flag The field name to look for + * @param out The index will be stored in this value + * @return True if the field is available, false otherwise + */ + virtual bool GetFieldIndex(char flag, size_t& out) const = 0; + protected: Request() : fuzzy_match(false) diff --git a/include/xline.h b/include/xline.h index 2688ac134..819e8bb43 100644 --- a/include/xline.h +++ b/include/xline.h @@ -515,8 +515,9 @@ class CoreExport XLineManager /** Expire a line given two iterators which identify it in the main map. * @param container Iterator to the first level of entries the map * @param item Iterator to the second level of entries in the map + * @param silent If true, doesn't send an expiry SNOTICE. */ - void ExpireLine(ContainerIter container, LookupIter item); + void ExpireLine(ContainerIter container, LookupIter item, bool silent = false); /** Apply any new lines that are pending to be applied. * This will only apply lines in the pending_lines list, to save on @@ -533,6 +534,6 @@ class CoreExport XLineManager */ void InvokeStats(const std::string& type, unsigned int numeric, Stats::Context& stats); - /** Clears any XLines which were added by the server configuration. */ - void ClearConfigLines(); + /** Expire X-lines which were added by the server configuration and have been removed. */ + void ExpireRemovedConfigLines(const std::string& type, const insp::flat_set<std::string>& configlines); }; diff --git a/locales/readme.txt b/locales/readme.txt index 069e664b5..5e366d606 100755 --- a/locales/readme.txt +++ b/locales/readme.txt @@ -1,6 +1,6 @@ Here you can find locales configuration files. -(!) The idea and several locale files are derived from Bynets UnrealIRCd distribution (See http://www.bynets.org/) +(!) The idea and several locale files are derived from Bynets UnrealIRCd distribution (See https://bynets.org) *** File structure *** diff --git a/make/template/inspircd.service b/make/template/inspircd.service index c05e61822..e29aa593f 100644 --- a/make/template/inspircd.service +++ b/make/template/inspircd.service @@ -30,6 +30,8 @@ ExecStop=@SCRIPT_DIR@/inspircd stop PIDFile=@DATA_DIR@/inspircd.pid Restart=on-failure Type=forking +User=@USER@ +Group=@GROUP@ [Install] WantedBy=multi-user.target diff --git a/make/template/main.mk b/make/template/main.mk index c3e4fdc7d..78f0cd798 100644 --- a/make/template/main.mk +++ b/make/template/main.mk @@ -188,7 +188,7 @@ std-header: @echo "* *" @echo "* This will take a *long* time. *" @echo "* Why not read our wiki at *" - @echo "* http://wiki.inspircd.org *" + @echo "* https://wiki.inspircd.org *" @echo "* while you wait for Make to run? *" @echo "*************************************" diff --git a/src/cidr.cpp b/src/cidr.cpp index 250ad9c69..377611437 100644 --- a/src/cidr.cpp +++ b/src/cidr.cpp @@ -73,7 +73,11 @@ bool irc::sockets::MatchCIDR(const std::string &address, const std::string &cidr } irc::sockets::sockaddrs addr; - irc::sockets::aptosa(address_copy, 0, addr); + if (!irc::sockets::aptosa(address_copy, 0, addr)) + { + // The address could not be parsed. + return false; + } irc::sockets::cidr_mask mask(cidr_copy); irc::sockets::cidr_mask mask2(addr, mask.length); diff --git a/src/clientprotocol.cpp b/src/clientprotocol.cpp index 212d65d6b..ee3909fbf 100644 --- a/src/clientprotocol.cpp +++ b/src/clientprotocol.cpp @@ -63,7 +63,7 @@ const ClientProtocol::SerializedMessage& ClientProtocol::Serializer::SerializeFo if (!msg.msginit_done) { msg.msginit_done = true; - FOREACH_MOD_CUSTOM(evprov, MessageTagProvider, OnClientProtocolPopulateTags, (msg)); + FOREACH_MOD_CUSTOM(evprov, MessageTagProvider, OnPopulateTags, (msg)); } return msg.GetSerialized(Message::SerializedInfo(this, MakeTagWhitelist(user, msg.GetTags()))); } diff --git a/src/configreader.cpp b/src/configreader.cpp index 675bc4721..b844be382 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -75,6 +75,8 @@ ServerConfig::~ServerConfig() static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::string& key, XLineFactory* make) { + insp::flat_set<std::string> configlines; + ConfigTagList tags = conf->ConfTags(tag); for(ConfigIter i = tags.first; i != tags.second; ++i) { @@ -85,9 +87,12 @@ static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::str std::string reason = ctag->getString("reason", "<Config>"); XLine* xl = make->Generate(ServerInstance->Time(), 0, "<Config>", reason, mask); xl->from_config = true; + configlines.insert(xl->Displayable()); if (!ServerInstance->XLines->AddLine(xl, NULL)) delete xl; } + + ServerInstance->XLines->ExpireRemovedConfigLines(make->GetType(), configlines); } typedef std::map<std::string, ConfigTag*> LocalIndex; @@ -310,6 +315,23 @@ void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current) } } +static std::string GetServerName() +{ +#ifndef _WIN32 + char hostname[256]; + if (gethostname(hostname, sizeof(hostname)) == 0) + { + std::string name(hostname); + if (name.find('.') == std::string::npos) + name.push_back('.'); + + if (name.length() <= ServerInstance->Config->Limits.MaxHost && InspIRCd::IsHost(name)) + return name; + } +#endif + return "irc.example.com"; +} + void ServerConfig::Fill() { ConfigTag* options = ConfValue("options"); @@ -317,7 +339,7 @@ void ServerConfig::Fill() ConfigTag* server = ConfValue("server"); if (sid.empty()) { - ServerName = server->getString("name", "irc.example.com", InspIRCd::IsHost); + ServerName = server->getString("name", GetServerName(), InspIRCd::IsHost); sid = server->getString("id"); if (!sid.empty() && !InspIRCd::IsSID(sid)) @@ -374,7 +396,6 @@ void ServerConfig::Fill() SocketEngine::Close(socktest); } - ServerInstance->XLines->ClearConfigLines(); ReadXLine(this, "badip", "ipmask", ServerInstance->XLines->GetFactory("Z")); ReadXLine(this, "badnick", "nick", ServerInstance->XLines->GetFactory("Q")); ReadXLine(this, "badhost", "host", ServerInstance->XLines->GetFactory("K")); diff --git a/src/coremods/core_channel/cmd_invite.cpp b/src/coremods/core_channel/cmd_invite.cpp index cd77a6682..66f05340a 100644 --- a/src/coremods/core_channel/cmd_invite.cpp +++ b/src/coremods/core_channel/cmd_invite.cpp @@ -29,7 +29,7 @@ CommandInvite::CommandInvite(Module* parent, Invite::APIImpl& invapiimpl) , invapi(invapiimpl) { Penalty = 4; - syntax = "[<nick> <channel>]"; + syntax = "[<nick> <channel> [<time>]]"; } /** Handle /INVITE diff --git a/src/coremods/core_channel/cmd_join.cpp b/src/coremods/core_channel/cmd_join.cpp index 2caed9dc6..0e783d2b3 100644 --- a/src/coremods/core_channel/cmd_join.cpp +++ b/src/coremods/core_channel/cmd_join.cpp @@ -24,7 +24,7 @@ CommandJoin::CommandJoin(Module* parent) : SplitCommand(parent, "JOIN", 1, 2) { - syntax = "<channel>{,<channel>} {<key>{,<key>}}"; + syntax = "<channel>[,<channel>]+ [<key>[,<key>]+]"; Penalty = 2; } diff --git a/src/coremods/core_channel/cmd_kick.cpp b/src/coremods/core_channel/cmd_kick.cpp index 138a65eae..c08eca06b 100644 --- a/src/coremods/core_channel/cmd_kick.cpp +++ b/src/coremods/core_channel/cmd_kick.cpp @@ -24,7 +24,7 @@ CommandKick::CommandKick(Module* parent) : Command(parent, "KICK", 2, 3) { - syntax = "<channel> <nick>{,<nick>} [<reason>]"; + syntax = "<channel> <nick>[,<nick>]+ [:<reason>]"; } /** Handle /KICK @@ -65,7 +65,7 @@ CmdResult CommandKick::Handle(User* user, const Params& parameters) if (u->server->IsULine()) { - user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, "You may not kick a u-lined client"); + user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, "You may not kick a U-lined client"); return CMD_FAILURE; } } diff --git a/src/coremods/core_channel/cmd_names.cpp b/src/coremods/core_channel/cmd_names.cpp index 28273c903..a179cf9dc 100644 --- a/src/coremods/core_channel/cmd_names.cpp +++ b/src/coremods/core_channel/cmd_names.cpp @@ -27,7 +27,7 @@ CommandNames::CommandNames(Module* parent) , privatemode(parent, "private") , invisiblemode(parent, "invisible") { - syntax = "{<channel>{,<channel>}}"; + syntax = "<channel>[,<channel>]+"; } /** Handle /NAMES diff --git a/src/coremods/core_channel/cmd_topic.cpp b/src/coremods/core_channel/cmd_topic.cpp index 0417f1a0c..f0af2a0ad 100644 --- a/src/coremods/core_channel/cmd_topic.cpp +++ b/src/coremods/core_channel/cmd_topic.cpp @@ -29,7 +29,7 @@ CommandTopic::CommandTopic(Module* parent) , secretmode(parent, "secret") , topiclockmode(parent, "topiclock") { - syntax = "<channel> [<topic>]"; + syntax = "<channel> [:<topic>]"; Penalty = 2; } diff --git a/src/coremods/core_ison.cpp b/src/coremods/core_ison.cpp index a4f63959f..8dc70da33 100644 --- a/src/coremods/core_ison.cpp +++ b/src/coremods/core_ison.cpp @@ -30,7 +30,7 @@ class CommandIson : public SplitCommand CommandIson(Module* parent) : SplitCommand(parent, "ISON", 1) { - syntax = "<nick> {nick}"; + syntax = "<nick> [<nick>]+"; } /** Handle command. * @param parameters The parameters to the command diff --git a/src/coremods/core_message.cpp b/src/coremods/core_message.cpp index a4879e0e5..8f6213f4c 100644 --- a/src/coremods/core_message.cpp +++ b/src/coremods/core_message.cpp @@ -303,7 +303,7 @@ class CommandMessage : public Command , moderatedmode(parent, "moderated") , noextmsgmode(parent, "noextmsg") { - syntax = "<target>{,<target>} <message>"; + syntax = "<target>[,<target>]+ :<message>"; } /** Handle command. @@ -357,7 +357,7 @@ class CommandSQuery : public SplitCommand CommandSQuery(Module* Creator) : SplitCommand(Creator, "SQUERY", 2, 2) { - syntax = "<service> <message>"; + syntax = "<service> :<message>"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) override @@ -398,7 +398,7 @@ class CommandSQuery : public SplitCommand if (!FirePreEvents(user, msgtarget, msgdetails)) return CMD_FAILURE; - // The SQUERY command targets a service on a u-lined server. This can never + // The SQUERY command targets a service on a U-lined server. This can never // be on the server local to the source so we don't need to do any routing // logic and can forward it as a PRIVMSG. diff --git a/src/coremods/core_oper/cmd_die.cpp b/src/coremods/core_oper/cmd_die.cpp index 618a72267..ce3160f45 100644 --- a/src/coremods/core_oper/cmd_die.cpp +++ b/src/coremods/core_oper/cmd_die.cpp @@ -26,7 +26,7 @@ CommandDie::CommandDie(Module* parent) : Command(parent, "DIE", 1, 1) { flags_needed = 'o'; - syntax = "<server>"; + syntax = "<servername>"; } void DieRestart::SendError(const std::string& message) diff --git a/src/coremods/core_oper/cmd_kill.cpp b/src/coremods/core_oper/cmd_kill.cpp index 5b622a88d..1201d61a8 100644 --- a/src/coremods/core_oper/cmd_kill.cpp +++ b/src/coremods/core_oper/cmd_kill.cpp @@ -27,7 +27,7 @@ CommandKill::CommandKill(Module* parent) , protoev(parent, name) { flags_needed = 'o'; - syntax = "<nickname> <reason>"; + syntax = "<nick>[,<nick>]+ :<reason>"; translation = { TR_CUSTOM, TR_CUSTOM }; } diff --git a/src/coremods/core_oper/cmd_restart.cpp b/src/coremods/core_oper/cmd_restart.cpp index 8280bf338..83a5370fb 100644 --- a/src/coremods/core_oper/cmd_restart.cpp +++ b/src/coremods/core_oper/cmd_restart.cpp @@ -25,7 +25,7 @@ CommandRestart::CommandRestart(Module* parent) : Command(parent, "RESTART", 1, 1) { flags_needed = 'o'; - syntax = "<server>"; + syntax = "<servername>"; } CmdResult CommandRestart::Handle(User* user, const Params& parameters) diff --git a/src/coremods/core_serialize_rfc.cpp b/src/coremods/core_serialize_rfc.cpp index 837fa3802..b53a2ea29 100644 --- a/src/coremods/core_serialize_rfc.cpp +++ b/src/coremods/core_serialize_rfc.cpp @@ -32,7 +32,7 @@ class RFCSerializer : public ClientProtocol::Serializer static const std::string::size_type MAX_CLIENT_MESSAGE_TAG_LENGTH = 4095; /** The maximum size of server-originated message tags in an outgoing message including the `@`. */ - static const std::string::size_type MAX_SERVER_MESSAGE_TAG_LENGTH = 511; + static const std::string::size_type MAX_SERVER_MESSAGE_TAG_LENGTH = 4095; static void SerializeTags(const ClientProtocol::TagMap& tags, const ClientProtocol::TagSelection& tagwl, std::string& line); diff --git a/src/coremods/core_stats.cpp b/src/coremods/core_stats.cpp index a1917dbb9..52e08e1d6 100644 --- a/src/coremods/core_stats.cpp +++ b/src/coremods/core_stats.cpp @@ -44,7 +44,7 @@ class CommandStats : public Command , statsevprov(Creator, "event/stats") { allow_empty_last_param = false; - syntax = "<stats-symbol> [<servername>]"; + syntax = "<symbol> [<servername>]"; } /** Handle command. diff --git a/src/coremods/core_stub.cpp b/src/coremods/core_stub.cpp index 9d257e741..4bb613b8b 100644 --- a/src/coremods/core_stub.cpp +++ b/src/coremods/core_stub.cpp @@ -40,7 +40,7 @@ class CommandConnect : public Command : Command(parent, "CONNECT", 1) { flags_needed = 'o'; - syntax = "<servername>"; + syntax = "<servermask>"; } /** Handle command. @@ -126,7 +126,7 @@ class CommandSquit : public Command : Command(parent, "SQUIT", 1, 2) { flags_needed = 'o'; - syntax = "<servername>"; + syntax = "<servermask>"; } /** Handle command. diff --git a/src/coremods/core_user/cmd_away.cpp b/src/coremods/core_user/cmd_away.cpp index 50a586392..834e8711d 100644 --- a/src/coremods/core_user/cmd_away.cpp +++ b/src/coremods/core_user/cmd_away.cpp @@ -33,7 +33,7 @@ CommandAway::CommandAway(Module* parent) , awayevprov(parent) { allow_empty_last_param = false; - syntax = "[<message>]"; + syntax = "[:<message>]"; } /** Handle /AWAY diff --git a/src/coremods/core_user/cmd_mode.cpp b/src/coremods/core_user/cmd_mode.cpp index ef0a7580a..cc6f94992 100644 --- a/src/coremods/core_user/cmd_mode.cpp +++ b/src/coremods/core_user/cmd_mode.cpp @@ -26,7 +26,7 @@ CommandMode::CommandMode(Module* parent) : Command(parent, "MODE", 1) , seq(0) { - syntax = "<target> <modes> {<mode-parameters>}"; + syntax = "<target> [[(+|-)]<modes> [<mode-parameters>]]"; memset(&sent, 0, sizeof(sent)); } @@ -152,7 +152,8 @@ namespace // the user is a member of the channel. bool show_secret = chan->HasUser(user); - std::string& modes = num.push("+").GetParams().back(); + size_t modepos = num.push("+").GetParams().size() - 1; + std::string modes; std::string param; for (unsigned char chr = 65; chr < 123; ++chr) { @@ -182,6 +183,7 @@ namespace num.push(param); param.clear(); } + num.GetParams()[modepos].append(modes); } } diff --git a/src/coremods/core_user/cmd_part.cpp b/src/coremods/core_user/cmd_part.cpp index 2bc431ab3..9400eed93 100644 --- a/src/coremods/core_user/cmd_part.cpp +++ b/src/coremods/core_user/cmd_part.cpp @@ -25,7 +25,7 @@ CommandPart::CommandPart(Module* parent) : Command(parent, "PART", 1, 2) { Penalty = 5; - syntax = "<channel>{,<channel>} [<reason>]"; + syntax = "<channel>[,<channel>]+ [:<reason>]"; } CmdResult CommandPart::Handle(User* user, const Params& parameters) diff --git a/src/coremods/core_user/cmd_quit.cpp b/src/coremods/core_user/cmd_quit.cpp index b88fdde80..fbf69a388 100644 --- a/src/coremods/core_user/cmd_quit.cpp +++ b/src/coremods/core_user/cmd_quit.cpp @@ -26,7 +26,7 @@ CommandQuit::CommandQuit(Module* parent) , operquit("operquit", ExtensionItem::EXT_USER, parent) { works_before_reg = true; - syntax = "[<message>]"; + syntax = "[:<message>]"; } CmdResult CommandQuit::Handle(User* user, const Params& parameters) diff --git a/src/coremods/core_user/cmd_user.cpp b/src/coremods/core_user/cmd_user.cpp index 1a8b091f3..89b173909 100644 --- a/src/coremods/core_user/cmd_user.cpp +++ b/src/coremods/core_user/cmd_user.cpp @@ -33,7 +33,7 @@ CommandUser::CommandUser(Module* parent) allow_empty_last_param = false; works_before_reg = true; Penalty = 0; - syntax = "<username> <localhost> <remotehost> <realname>"; + syntax = "<username> <unused> <unused> :<realname>"; } CmdResult CommandUser::HandleLocal(LocalUser* user, const Params& parameters) diff --git a/src/coremods/core_userhost.cpp b/src/coremods/core_userhost.cpp index aaaf32627..c89ea2894 100644 --- a/src/coremods/core_userhost.cpp +++ b/src/coremods/core_userhost.cpp @@ -33,7 +33,7 @@ class CommandUserhost : public Command : Command(parent,"USERHOST", 1) , hideopermode(parent, "hideoper") { - syntax = "<nick> [<nick> ...]"; + syntax = "<nick> [<nick>]+"; } /** Handle command. * @param parameters The parameters to the command diff --git a/src/coremods/core_wallops.cpp b/src/coremods/core_wallops.cpp index da7ff4070..1c38f7228 100644 --- a/src/coremods/core_wallops.cpp +++ b/src/coremods/core_wallops.cpp @@ -36,7 +36,7 @@ class CommandWallops : public Command , protoevprov(parent, name) { flags_needed = 'o'; - syntax = "<any-text>"; + syntax = ":<message>"; } /** Handle command. diff --git a/src/coremods/core_who.cpp b/src/coremods/core_who.cpp index e43658821..ed590203a 100644 --- a/src/coremods/core_who.cpp +++ b/src/coremods/core_who.cpp @@ -34,8 +34,36 @@ enum RPL_WHOSPCRPL = 354 }; +static const char whox_field_order[] = "tcuihsnfdlaor"; +static const char who_field_order[] = "cuhsnf"; + struct WhoData : public Who::Request { + bool GetFieldIndex(char flag, size_t& out) const override + { + if (!whox) + { + const char* pos = strchr(who_field_order, flag); + if (pos == NULL) + return false; + + out = pos - who_field_order; + return true; + } + + if (!whox_fields[flag]) + return false; + + out = 0; + for (const char* c = whox_field_order; *c && *c != flag; ++c) + { + if (whox_fields[*c]) + ++out; + } + + return whox_field_order[out]; + } + WhoData(const CommandBase::Params& parameters) { // Find the matchtext and swap the 0 for a * so we can use InspIRCd::Match on it. @@ -143,7 +171,7 @@ class CommandWho : public SplitCommand , whoevprov(parent, "event/who") { allow_empty_last_param = false; - syntax = "<server>|<nickname>|<channel>|<realname>|<host>|0 [[Aafhilmnoprstux][%acdfhilnorstu] <server>|<nickname>|<channel>|<realname>|<host>|0]"; + syntax = "<server>|<nick>|<channel>|<realname>|<host>|0 [[Aafhilmnoprstux][%acdfhilnorstu] <server>|<nick>|<channel>|<realname>|<host>|0]"; } /** Sends a WHO reply to a user. */ diff --git a/src/coremods/core_whois.cpp b/src/coremods/core_whois.cpp index d07370deb..617230a82 100644 --- a/src/coremods/core_whois.cpp +++ b/src/coremods/core_whois.cpp @@ -107,7 +107,7 @@ class CommandWhois : public SplitCommand , lineevprov(parent, "event/whoisline") { Penalty = 2; - syntax = "<nick>{,<nick>}"; + syntax = "[<servername>] <nick>[,<nick>]+"; } /** Handle command. diff --git a/src/coremods/core_whowas.cpp b/src/coremods/core_whowas.cpp index 6b20f1526..d420cf598 100644 --- a/src/coremods/core_whowas.cpp +++ b/src/coremods/core_whowas.cpp @@ -37,7 +37,7 @@ enum CommandWhowas::CommandWhowas( Module* parent) : Command(parent, "WHOWAS", 1) { - syntax = "<nick>{,<nick>}"; + syntax = "<nick>"; Penalty = 2; } diff --git a/src/coremods/core_xline/cmd_eline.cpp b/src/coremods/core_xline/cmd_eline.cpp index 014393178..c1e2f2b2a 100644 --- a/src/coremods/core_xline/cmd_eline.cpp +++ b/src/coremods/core_xline/cmd_eline.cpp @@ -26,7 +26,7 @@ CommandEline::CommandEline(Module* parent) : Command(parent, "ELINE", 1, 3) { flags_needed = 'o'; - syntax = "<ident@host> [<duration> :<reason>]"; + syntax = "<user@host> [<duration> :<reason>]"; } /** Handle /ELINE @@ -69,14 +69,13 @@ CmdResult CommandEline::Handle(User* user, const Params& parameters) { if (!duration) { - ServerInstance->SNO.WriteToSnoMask('x',"%s added permanent E-line for %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added permanent E-line for %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); } else { - time_t c_requires_crap = duration + ServerInstance->Time(); - std::string timestr = InspIRCd::TimeString(c_requires_crap); - ServerInstance->SNO.WriteToSnoMask('x',"%s added timed E-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(), - timestr.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added timed E-line for %s, expires in %s (on %s): %s", + user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } } else diff --git a/src/coremods/core_xline/cmd_gline.cpp b/src/coremods/core_xline/cmd_gline.cpp index 3643324e3..0db0c42b2 100644 --- a/src/coremods/core_xline/cmd_gline.cpp +++ b/src/coremods/core_xline/cmd_gline.cpp @@ -26,7 +26,7 @@ CommandGline::CommandGline(Module* parent) : Command(parent, "GLINE", 1, 3) { flags_needed = 'o'; - syntax = "<ident@host> [<duration> :<reason>]"; + syntax = "<user@host> [<duration> :<reason>]"; } /** Handle /GLINE @@ -75,14 +75,13 @@ CmdResult CommandGline::Handle(User* user, const Params& parameters) { if (!duration) { - ServerInstance->SNO.WriteToSnoMask('x',"%s added permanent G-line for %s: %s",user->nick.c_str(),target.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added permanent G-line for %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); } else { - time_t c_requires_crap = duration + ServerInstance->Time(); - std::string timestr = InspIRCd::TimeString(c_requires_crap); - ServerInstance->SNO.WriteToSnoMask('x',"%s added timed G-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(), - timestr.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added timed G-line for %s, expires in %s (on %s): %s", + user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); diff --git a/src/coremods/core_xline/cmd_kline.cpp b/src/coremods/core_xline/cmd_kline.cpp index 3fb58c171..6917ee66a 100644 --- a/src/coremods/core_xline/cmd_kline.cpp +++ b/src/coremods/core_xline/cmd_kline.cpp @@ -26,7 +26,7 @@ CommandKline::CommandKline(Module* parent) : Command(parent, "KLINE", 1, 3) { flags_needed = 'o'; - syntax = "<ident@host> [<duration> :<reason>]"; + syntax = "<user@host> [<duration> :<reason>]"; } /** Handle /KLINE @@ -75,14 +75,13 @@ CmdResult CommandKline::Handle(User* user, const Params& parameters) { if (!duration) { - ServerInstance->SNO.WriteToSnoMask('x',"%s added permanent K-line for %s: %s",user->nick.c_str(),target.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added permanent K-line for %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); } else { - time_t c_requires_crap = duration + ServerInstance->Time(); - std::string timestr = InspIRCd::TimeString(c_requires_crap); - ServerInstance->SNO.WriteToSnoMask('x',"%s added timed K-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(), - timestr.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added timed K-line for %s, expires in %s (on %s): %s", + user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); diff --git a/src/coremods/core_xline/cmd_qline.cpp b/src/coremods/core_xline/cmd_qline.cpp index d58cefbaa..c93c15a12 100644 --- a/src/coremods/core_xline/cmd_qline.cpp +++ b/src/coremods/core_xline/cmd_qline.cpp @@ -27,7 +27,7 @@ CommandQline::CommandQline(Module* parent) : Command(parent, "QLINE", 1, 3) { flags_needed = 'o'; - syntax = "<nick> [<duration> :<reason>]"; + syntax = "<nickmask> [<duration> :<reason>]"; } CmdResult CommandQline::Handle(User* user, const Params& parameters) @@ -55,14 +55,13 @@ CmdResult CommandQline::Handle(User* user, const Params& parameters) { if (!duration) { - ServerInstance->SNO.WriteToSnoMask('x',"%s added permanent Q-line for %s: %s",user->nick.c_str(), parameters[0].c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added permanent Q-line for %s: %s", user->nick.c_str(), parameters[0].c_str(), parameters[2].c_str()); } else { - time_t c_requires_crap = duration + ServerInstance->Time(); - std::string timestr = InspIRCd::TimeString(c_requires_crap); - ServerInstance->SNO.WriteToSnoMask('x',"%s added timed Q-line for %s, expires on %s: %s",user->nick.c_str(),parameters[0].c_str(), - timestr.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added timed Q-line for %s, expires in %s (on %s): %s", + user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } diff --git a/src/coremods/core_xline/cmd_zline.cpp b/src/coremods/core_xline/cmd_zline.cpp index 13e161491..9eb1c1b7f 100644 --- a/src/coremods/core_xline/cmd_zline.cpp +++ b/src/coremods/core_xline/cmd_zline.cpp @@ -73,14 +73,13 @@ CmdResult CommandZline::Handle(User* user, const Params& parameters) { if (!duration) { - ServerInstance->SNO.WriteToSnoMask('x',"%s added permanent Z-line for %s: %s", user->nick.c_str(), ipaddr, parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added permanent Z-line for %s: %s", user->nick.c_str(), ipaddr, parameters[2].c_str()); } else { - time_t c_requires_crap = duration + ServerInstance->Time(); - std::string timestr = InspIRCd::TimeString(c_requires_crap); - ServerInstance->SNO.WriteToSnoMask('x',"%s added timed Z-line for %s, expires on %s: %s",user->nick.c_str(),ipaddr, - timestr.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added timed Z-line for %s, expires in %s (on %s): %s", + user->nick.c_str(), ipaddr, InspIRCd::DurationString(duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); } diff --git a/src/helperfuncs.cpp b/src/helperfuncs.cpp index e291fd975..6a09e6357 100644 --- a/src/helperfuncs.cpp +++ b/src/helperfuncs.cpp @@ -7,6 +7,7 @@ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org> * Copyright (C) 2006-2007 Oliver Lupton <oliverlupton@gmail.com> * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> + * Copyright (C) 2003-2019 Anope Team <team@anope.org> * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public @@ -429,6 +430,33 @@ bool InspIRCd::IsValidDuration(const std::string& duration) return true; } +std::string InspIRCd::DurationString(time_t duration) +{ + time_t years = duration / 31536000; + time_t weeks = (duration / 604800) % 52; + time_t days = (duration / 86400) % 7; + time_t hours = (duration / 3600) % 24; + time_t minutes = (duration / 60) % 60; + time_t seconds = duration % 60; + + std::string ret; + + if (years) + ret = ConvToStr(years) + "y"; + if (weeks) + ret += ConvToStr(weeks) + "w"; + if (days) + ret += ConvToStr(days) + "d"; + if (hours) + ret += ConvToStr(hours) + "h"; + if (minutes) + ret += ConvToStr(minutes) + "m"; + if (seconds) + ret += ConvToStr(seconds) + "s"; + + return ret; +} + std::string InspIRCd::Format(va_list& vaList, const char* formatString) { static std::vector<char> formatBuffer(1024); diff --git a/src/mode.cpp b/src/mode.cpp index 0eddd5365..91ce989cf 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -312,18 +312,18 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode } } - if ((adding) && (IS_LOCAL(user)) && (mh->NeedsOper()) && (!user->HasModePermission(mh))) + if ((chan || (!chan && adding)) && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(mh)) { /* It's an oper only mode, and they don't have access to it. */ if (user->IsOper()) { - user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to set %s mode %c", - user->oper->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar)); + user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to %sset %s mode %c", + user->oper->name.c_str(), adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar)); } else { - user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Only operators may set %s mode %c", - type == MODETYPE_CHANNEL ? "channel" : "user", modechar)); + user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Only operators may %sset %s mode %c", + adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar)); } return MODEACTION_DENY; } @@ -592,13 +592,13 @@ void ModeParser::AddMode(ModeHandler* mh) PrefixMode* otherpm = FindPrefix(pm->GetPrefix()); if (otherpm) - throw ModuleException(InspIRCd::Format("Mode prefix for %s already by used by %s from %s: %c", + throw ModuleException(InspIRCd::Format("Mode prefix for %s already used by %s from %s: %c", mh->name.c_str(), otherpm->name.c_str(), otherpm->creator->ModuleSourceFile.c_str(), pm->GetPrefix())); } ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65]; if (slot) - throw ModuleException(InspIRCd::Format("Mode letter for %s already by used by %s from %s: %c", + throw ModuleException(InspIRCd::Format("Mode letter for %s already used by %s from %s: %c", mh->name.c_str(), slot->name.c_str(), slot->creator->ModuleSourceFile.c_str(), mh->GetModeChar())); // The mode needs an id if it is either a user mode, a simple mode (flag) or a parameter mode. diff --git a/src/modules.cpp b/src/modules.cpp index e17138da0..e98351c15 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -467,6 +467,7 @@ void ModuleManager::LoadAll() std::map<std::string, ServiceList> servicemap; LoadCoreModules(servicemap); + // Step 1: load all of the modules. ConfigTagList tags = ServerInstance->Config->ConfTags("module"); for (ConfigIter i = tags.first; i != tags.second; ++i) { @@ -487,8 +488,7 @@ void ModuleManager::LoadAll() } } - ConfigStatus confstatus; - + // Step 2: initialize the modules and register their services. for (ModuleMap::const_iterator i = Modules.begin(); i != Modules.end(); ++i) { Module* mod = i->second; @@ -498,7 +498,6 @@ void ModuleManager::LoadAll() AttachAll(mod); AddServices(servicemap[i->first]); mod->init(); - mod->ReadConfig(confstatus); } catch (CoreException& modexcept) { @@ -510,6 +509,27 @@ void ModuleManager::LoadAll() } this->NewServices = NULL; + ConfigStatus confstatus; + + // Step 3: Read the configuration for the modules. This must be done as part of + // its own step so that services provided by modules can be registered before + // the configuration is read. + for (ModuleMap::const_iterator i = Modules.begin(); i != Modules.end(); ++i) + { + Module* mod = i->second; + try + { + ServerInstance->Logs.Log("MODULE", LOG_DEBUG, "Reading configuration for %s", i->first.c_str()); + mod->ReadConfig(confstatus); + } + catch (CoreException& modexcept) + { + LastModuleError = "Unable to read the configuration for " + mod->ModuleSourceFile + ": " + modexcept.GetReason(); + ServerInstance->Logs.Log("MODULE", LOG_DEFAULT, LastModuleError); + std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl; + ServerInstance->Exit(EXIT_STATUS_CONFIG); + } + } if (!PrioritizeHooks()) ServerInstance->Exit(EXIT_STATUS_MODULE); diff --git a/src/modules/extra/README b/src/modules/extra/README index b59494df9..630ab3e85 100644 --- a/src/modules/extra/README +++ b/src/modules/extra/README @@ -2,7 +2,7 @@ This directory stores modules which require external libraries to compile. For example, m_filter_pcre requires the PCRE libraries. To compile any of these modules first ensure you have the required dependencies -(read the online documentation at https://wiki.inspircd.org/) and then symlink +(read the online documentation at https://wiki.inspircd.org) and then symlink the .cpp file from this directory into the parent directory (src/modules/). Alternatively, use the command: ./configure --enable-extras=m_extra.cpp, which will diff --git a/src/modules/m_botmode.cpp b/src/modules/m_botmode.cpp index 1bb06e687..a86e9116f 100644 --- a/src/modules/m_botmode.cpp +++ b/src/modules/m_botmode.cpp @@ -20,6 +20,7 @@ #include "inspircd.h" +#include "modules/cap.h" #include "modules/whois.h" enum @@ -28,13 +29,44 @@ enum RPL_WHOISBOT = 335 }; +class BotTag : public ClientProtocol::MessageTagProvider +{ + private: + SimpleUserModeHandler& botmode; + Cap::Reference ctctagcap; + + public: + BotTag(Module* mod, SimpleUserModeHandler& bm) + : ClientProtocol::MessageTagProvider(mod) + , botmode(bm) + , ctctagcap(mod, "message-tags") + { + } + + void OnPopulateTags(ClientProtocol::Message& msg) override + { + User* const user = msg.GetSourceUser(); + if (user && user->IsModeSet(botmode)) + msg.AddTag("inspircd.org/bot", this, ""); + } + + bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) override + { + return ctctagcap.get(user); + } +}; + class ModuleBotMode : public Module, public Whois::EventListener { + private: SimpleUserModeHandler bm; + BotTag tag; + public: ModuleBotMode() : Whois::EventListener(this) , bm(this, "bot", 'B') + , tag(this, bm) { } diff --git a/src/modules/m_callerid.cpp b/src/modules/m_callerid.cpp index b8ffd6f62..470db5543 100644 --- a/src/modules/m_callerid.cpp +++ b/src/modules/m_callerid.cpp @@ -179,7 +179,7 @@ public: extInfo(Creator) { allow_empty_last_param = false; - syntax = "*|(+|-)<nick>[,(+|-)<nick> ...]"; + syntax = "*|(+|-)<nick>[,(+|-)<nick>]+"; translation = { TR_CUSTOM }; } @@ -189,7 +189,7 @@ public: if (parameter.find(',') != std::string::npos) return; - // Convert a [+|-]<nick> into a [-]<uuid> + // Convert a (+|-)<nick> into a [-]<uuid> ACCEPTAction action = GetTargetAndAction(parameter); if (!action.first) return; diff --git a/src/modules/m_cban.cpp b/src/modules/m_cban.cpp index a9f0e50eb..316b6dc2c 100644 --- a/src/modules/m_cban.cpp +++ b/src/modules/m_cban.cpp @@ -88,7 +88,7 @@ class CommandCBan : public Command public: CommandCBan(Module* Creator) : Command(Creator, "CBAN", 1, 3) { - flags_needed = 'o'; this->syntax = "<channel> [<duration> :<reason>]"; + flags_needed = 'o'; this->syntax = "<channel> [<duration> [:<reason>]]"; } CmdResult Handle(User* user, const Params& parameters) override @@ -130,9 +130,9 @@ class CommandCBan : public Command } else { - time_t c_requires_crap = duration + ServerInstance->Time(); - std::string timestr = InspIRCd::TimeString(c_requires_crap); - ServerInstance->SNO.WriteGlobalSno('x', "%s added timed CBan for %s, expires on %s: %s", user->nick.c_str(), parameters[0].c_str(), timestr.c_str(), reason); + ServerInstance->SNO.WriteGlobalSno('x', "%s added timed CBan for %s, expires in %s (on %s): %s", + user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), reason); } } else diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index 890a8f302..8a028f546 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -132,7 +132,7 @@ class CommandWebIRC : public SplitCommand { allow_empty_last_param = false; works_before_reg = true; - this->syntax = "<password> <gateway> <hostname> <ip> [flags]"; + this->syntax = "<password> <gateway> <hostname> <ip> [<flags>]"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) override diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index ae459c6df..24afa4882 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -146,7 +146,7 @@ class CommandCheck : public Command : Command(parent,"CHECK", 1) , snomaskmode(parent, "snomask") { - flags_needed = 'o'; syntax = "<nickname>|<ip>|<hostmask>|<channel> <server>"; + flags_needed = 'o'; syntax = "<nick>|<ipmask>|<hostmask>|<channel> [<servername>]"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_chghost.cpp b/src/modules/m_chghost.cpp index 46e644551..0bcc5ab91 100644 --- a/src/modules/m_chghost.cpp +++ b/src/modules/m_chghost.cpp @@ -33,7 +33,7 @@ class CommandChghost : public Command { allow_empty_last_param = false; flags_needed = 'o'; - syntax = "<nick> <newhost>"; + syntax = "<nick> <host>"; translation = { TR_NICK, TR_TEXT }; } diff --git a/src/modules/m_chgident.cpp b/src/modules/m_chgident.cpp index 28a144336..8ff609b29 100644 --- a/src/modules/m_chgident.cpp +++ b/src/modules/m_chgident.cpp @@ -31,7 +31,7 @@ class CommandChgident : public Command { allow_empty_last_param = false; flags_needed = 'o'; - syntax = "<nick> <newident>"; + syntax = "<nick> <ident>"; translation = { TR_NICK, TR_TEXT }; } diff --git a/src/modules/m_chgname.cpp b/src/modules/m_chgname.cpp index 65999b142..cf0c2d8ee 100644 --- a/src/modules/m_chgname.cpp +++ b/src/modules/m_chgname.cpp @@ -29,7 +29,7 @@ class CommandChgname : public Command { allow_empty_last_param = false; flags_needed = 'o'; - syntax = "<nick> <new real name>"; + syntax = "<nick> :<realname>"; translation = { TR_NICK, TR_TEXT }; } diff --git a/src/modules/m_clearchan.cpp b/src/modules/m_clearchan.cpp index dd2ab6390..f5f8a6dde 100644 --- a/src/modules/m_clearchan.cpp +++ b/src/modules/m_clearchan.cpp @@ -28,7 +28,7 @@ class CommandClearChan : public Command CommandClearChan(Module* Creator) : Command(Creator, "CLEARCHAN", 1, 3) { - syntax = "<channel> [<KILL|KICK|G|Z>] [<reason>]"; + syntax = "<channel> [KILL|KICK|G|Z] [:<reason>]"; flags_needed = 'o'; // Stop the linking mod from forwarding ENCAP'd CLEARCHAN commands, see below why diff --git a/src/modules/m_customtitle.cpp b/src/modules/m_customtitle.cpp index 6b81a7932..5ddde6c68 100644 --- a/src/modules/m_customtitle.cpp +++ b/src/modules/m_customtitle.cpp @@ -74,7 +74,7 @@ class CommandTitle : public Command CommandTitle(Module* Creator) : Command(Creator,"TITLE", 2), ctitle("ctitle", ExtensionItem::EXT_USER, Creator) { - syntax = "<user> <password>"; + syntax = "<username> <password>"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_cycle.cpp b/src/modules/m_cycle.cpp index e9c9580e5..5d71384c5 100644 --- a/src/modules/m_cycle.cpp +++ b/src/modules/m_cycle.cpp @@ -28,7 +28,7 @@ class CommandCycle : public SplitCommand CommandCycle(Module* Creator) : SplitCommand(Creator, "CYCLE", 1) { - Penalty = 3; syntax = "<channel> :[reason]"; + Penalty = 3; syntax = "<channel> [:<reason>]"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) override diff --git a/src/modules/m_dccallow.cpp b/src/modules/m_dccallow.cpp index 94ddcce02..5fefd75e5 100644 --- a/src/modules/m_dccallow.cpp +++ b/src/modules/m_dccallow.cpp @@ -54,7 +54,7 @@ static const char* const helptext[] = "Brain would then be able to send you files. They would have to", "resend the file again if the server gave them an error message", "before you added them to your DCCALLOW list.", - "DCCALLOW entries will be temporary by default, if you want to add", + "DCCALLOW entries will be temporary. If you want to add", "them to your DCCALLOW list until you leave IRC, type:", "/DCCALLOW +Brain 0", "To remove the user from your DCCALLOW list, type:", @@ -63,7 +63,7 @@ static const char* const helptext[] = "/DCCALLOW LIST", "NOTE: If the user leaves IRC or changes their nickname", " they will be removed from your DCCALLOW list.", - " your DCCALLOW list will be deleted when you leave IRC." + " Your DCCALLOW list will be deleted when you leave IRC." }; class BannedFileList @@ -117,7 +117,7 @@ class CommandDccallow : public Command CmdResult Handle(User* user, const Params& parameters) override { - /* syntax: DCCALLOW [+|-]<nick> (<time>) */ + /* syntax: DCCALLOW [(+|-)<nick> [<time>]]|[LIST|HELP] */ if (!parameters.size()) { // display current DCCALLOW list @@ -235,7 +235,7 @@ class CommandDccallow : public Command if (length > 0) { - user->WriteNumeric(RPL_DCCALLOWTIMED, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for %ld seconds", target->nick.c_str(), length)); + user->WriteNumeric(RPL_DCCALLOWTIMED, user->nick, InspIRCd::Format("Added %s to DCCALLOW list for %s", target->nick.c_str(), InspIRCd::DurationString(length).c_str())); } else { diff --git a/src/modules/m_delayjoin.cpp b/src/modules/m_delayjoin.cpp index 8afb27c92..17036a398 100644 --- a/src/modules/m_delayjoin.cpp +++ b/src/modules/m_delayjoin.cpp @@ -21,6 +21,7 @@ #include "inspircd.h" +#include "modules/ctctags.h" class DelayJoinMode : public ModeHandler { @@ -72,7 +73,9 @@ class JoinHook : public ClientProtocol::EventHook } -class ModuleDelayJoin : public Module +class ModuleDelayJoin + : public Module + , public CTCTags::EventListener { public: LocalIntExt unjoined; @@ -80,7 +83,8 @@ class ModuleDelayJoin : public Module DelayJoinMode djm; ModuleDelayJoin() - : unjoined("delayjoin", ExtensionItem::EXT_MEMBERSHIP, this) + : CTCTags::EventListener(this) + , unjoined("delayjoin", ExtensionItem::EXT_MEMBERSHIP, this) , joinhook(this, unjoined) , djm(this, unjoined) { @@ -94,6 +98,7 @@ class ModuleDelayJoin : public Module void OnUserKick(User* source, Membership*, const std::string &reason, CUList&) override; void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) override; void OnUserMessage(User* user, const MessageTarget& target, const MessageDetails& details) override; + void OnUserTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) override; ModResult OnRawMode(User* user, Channel* channel, ModeHandler* mh, const std::string& param, bool adding) override; }; @@ -176,6 +181,15 @@ void ModuleDelayJoin::OnBuildNeighborList(User* source, IncludeChanList& include } } +void ModuleDelayJoin::OnUserTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) +{ + if (target.type != MessageTarget::TYPE_CHANNEL) + return; + + Channel* channel = target.Get<Channel>(); + djm.RevealUser(user, channel); +} + void ModuleDelayJoin::OnUserMessage(User* user, const MessageTarget& target, const MessageDetails& details) { if (target.type != MessageTarget::TYPE_CHANNEL) diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index 02bd90aea..8fcf5c12f 100644 --- a/src/modules/m_dnsbl.cpp +++ b/src/modules/m_dnsbl.cpp @@ -147,9 +147,9 @@ class DNSBLResolver : public DNS::Request "*", them->GetIPString()); if (ServerInstance->XLines->AddLine(kl,NULL)) { - std::string timestr = InspIRCd::TimeString(kl->expiry); - ServerInstance->SNO.WriteGlobalSno('x', "K-line added due to DNSBL match on *@%s to expire on %s: %s", - them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + ServerInstance->SNO.WriteGlobalSno('x', "K-line added due to DNSBL match on *@%s to expire in %s (on %s): %s", + them->GetIPString().c_str(), InspIRCd::DurationString(kl->duration).c_str(), + InspIRCd::TimeString(kl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); } else @@ -165,9 +165,9 @@ class DNSBLResolver : public DNS::Request "*", them->GetIPString()); if (ServerInstance->XLines->AddLine(gl,NULL)) { - std::string timestr = InspIRCd::TimeString(gl->expiry); - ServerInstance->SNO.WriteGlobalSno('x', "G-line added due to DNSBL match on *@%s to expire on %s: %s", - them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + ServerInstance->SNO.WriteGlobalSno('x', "G-line added due to DNSBL match on *@%s to expire in %s (on %s): %s", + them->GetIPString().c_str(), InspIRCd::DurationString(gl->duration).c_str(), + InspIRCd::TimeString(gl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); } else @@ -183,9 +183,9 @@ class DNSBLResolver : public DNS::Request them->GetIPString()); if (ServerInstance->XLines->AddLine(zl,NULL)) { - std::string timestr = InspIRCd::TimeString(zl->expiry); - ServerInstance->SNO.WriteGlobalSno('x', "Z-line added due to DNSBL match on %s to expire on %s: %s", - them->GetIPString().c_str(), timestr.c_str(), reason.c_str()); + ServerInstance->SNO.WriteGlobalSno('x', "Z-line added due to DNSBL match on %s to expire in %s (on %s): %s", + them->GetIPString().c_str(), InspIRCd::DurationString(zl->duration).c_str(), + InspIRCd::TimeString(zl->expiry).c_str(), reason.c_str()); ServerInstance->XLines->ApplyLines(); } else diff --git a/src/modules/m_filter.cpp b/src/modules/m_filter.cpp index 313038276..ebc1ae1f7 100644 --- a/src/modules/m_filter.cpp +++ b/src/modules/m_filter.cpp @@ -155,7 +155,7 @@ class CommandFilter : public Command : Command(f, "FILTER", 1, 5) { flags_needed = 'o'; - this->syntax = "<filter-definition> <action> <flags> [<duration>] :<reason>"; + this->syntax = "<pattern> [<action> <flags> [<duration>] :<reason>]"; } CmdResult Handle(User* user, const Params& parameters) override; @@ -192,8 +192,8 @@ class ModuleFilter : public Module, public ServerEventListener, public Stats::Ev CullResult cull() override; ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) override; FilterResult* FilterMatch(User* user, const std::string &text, int flags); - bool DeleteFilter(const std::string &freeform); - std::pair<bool, std::string> AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flags); + bool DeleteFilter(const std::string& freeform, std::string& reason); + std::pair<bool, std::string> AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flags, bool config = false); void ReadConfig(ConfigStatus& status) override; Version GetVersion() override; std::string EncodeFilter(FilterResult* filter); @@ -214,11 +214,14 @@ CmdResult CommandFilter::Handle(User* user, const Params& parameters) if (parameters.size() == 1) { /* Deleting a filter */ - Module *me = creator; - if (static_cast<ModuleFilter *>(me)->DeleteFilter(parameters[0])) + Module* me = creator; + std::string reason; + + if (static_cast<ModuleFilter*>(me)->DeleteFilter(parameters[0], reason)) { - user->WriteNotice("*** Removed filter '" + parameters[0] + "'"); - ServerInstance->SNO.WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', "FILTER: "+user->nick+" removed filter '"+parameters[0]+"'"); + user->WriteNotice("*** Removed filter '" + parameters[0] + "': " + reason); + ServerInstance->SNO.WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', "%s removed filter '%s': %s", + user->nick.c_str(), parameters[0].c_str(), reason.c_str()); return CMD_SUCCESS; } else @@ -269,15 +272,19 @@ CmdResult CommandFilter::Handle(User* user, const Params& parameters) reasonindex = 3; } - Module *me = creator; - std::pair<bool, std::string> result = static_cast<ModuleFilter *>(me)->AddFilter(freeform, type, parameters[reasonindex], duration, flags); + Module* me = creator; + std::pair<bool, std::string> result = static_cast<ModuleFilter*>(me)->AddFilter(freeform, type, parameters[reasonindex], duration, flags); if (result.first) { - user->WriteNotice("*** Added filter '" + freeform + "', type '" + parameters[1] + "'" + - (duration ? ", duration " + parameters[3] : "") + ", flags '" + flags + "', reason: '" + - parameters[reasonindex] + "'"); + const std::string message = InspIRCd::Format("'%s', type '%s'%s, flags '%s', reason: %s", + freeform.c_str(), parameters[1].c_str(), + (duration ? InspIRCd::Format(", duration '%s'", + InspIRCd::DurationString(duration).c_str()).c_str() + : ""), flags.c_str(), parameters[reasonindex].c_str()); - ServerInstance->SNO.WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', "FILTER: "+user->nick+" added filter '"+freeform+"', type '"+parameters[1]+"', "+(duration ? "duration "+parameters[3]+", " : "")+"flags '"+flags+"', reason: "+parameters[reasonindex]); + user->WriteNotice("*** Added filter " + message); + ServerInstance->SNO.WriteToSnoMask(IS_LOCAL(user) ? 'f' : 'F', + "%s added filter %s", user->nick.c_str(), message.c_str()); return CMD_SUCCESS; } @@ -409,8 +416,10 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar else if (f->action == FA_SHUN && (ServerInstance->XLines->GetFactory("SHUN"))) { Shun* sh = new Shun(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString()); - ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was shunned because their message to %s matched %s (%s)", - user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); + ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was shunned for %s (expires on %s) because their message to %s matched %s (%s)", + user->nick.c_str(), sh->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), + target.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(sh, NULL)) { ServerInstance->XLines->ApplyLines(); @@ -421,8 +430,10 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar else if (f->action == FA_GLINE) { GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString()); - ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was G-lined because their message to %s matched %s (%s)", - user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); + ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was G-lined for %s (expires on %s) because their message to %s matched %s (%s)", + user->nick.c_str(), gl->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), + target.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(gl,NULL)) { ServerInstance->XLines->ApplyLines(); @@ -433,8 +444,10 @@ ModResult ModuleFilter::OnUserPreMessage(User* user, const MessageTarget& msgtar else if (f->action == FA_ZLINE) { ZLine* zl = new ZLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString()); - ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was Z-lined because their message to %s matched %s (%s)", - user->nick.c_str(), target.c_str(), f->freeform.c_str(), f->reason.c_str())); + ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was Z-lined for %s (expires on %s) because their message to %s matched %s (%s)", + user->nick.c_str(), zl->Displayable().c_str(), InspIRCd::DurationString(f->duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), + target.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(zl,NULL)) { ServerInstance->XLines->ApplyLines(); @@ -508,8 +521,11 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params& { /* Note: We G-line *@IP so that if their host doesn't resolve the G-line still applies. */ GLine* gl = new GLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), "*", user->GetIPString()); - ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was G-lined because their %s message matched %s (%s)", - user->nick.c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str())); + ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was G-lined for %s (expires on %s) because their %s message matched %s (%s)", + user->nick.c_str(), gl->Displayable().c_str(), + InspIRCd::DurationString(f->duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), + command.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(gl,NULL)) { @@ -521,8 +537,11 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params& if (f->action == FA_ZLINE) { ZLine* zl = new ZLine(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString()); - ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was Z-lined because their %s message matched %s (%s)", - user->nick.c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str())); + ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was Z-lined for %s (expires on %s) because their %s message matched %s (%s)", + user->nick.c_str(), zl->Displayable().c_str(), + InspIRCd::DurationString(f->duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), + command.c_str(), f->freeform.c_str(), f->reason.c_str())); if (ServerInstance->XLines->AddLine(zl,NULL)) { @@ -535,8 +554,12 @@ ModResult ModuleFilter::OnPreCommand(std::string& command, CommandBase::Params& { /* Note: We shun *!*@IP so that if their host doesnt resolve the shun still applies. */ Shun* sh = new Shun(ServerInstance->Time(), f->duration, ServerInstance->Config->ServerName.c_str(), f->reason.c_str(), user->GetIPString()); - ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s was shunned because their %s message matched %s (%s)", - user->nick.c_str(), command.c_str(), f->freeform.c_str(), f->reason.c_str())); + ServerInstance->SNO.WriteGlobalSno('f', InspIRCd::Format("%s (%s) was shunned for %s (expires on %s) because their %s message matched %s (%s)", + user->nick.c_str(), sh->Displayable().c_str(), + InspIRCd::DurationString(f->duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + f->duration).c_str(), + command.c_str(), f->freeform.c_str(), f->reason.c_str())); + if (ServerInstance->XLines->AddLine(sh, NULL)) { ServerInstance->XLines->ApplyLines(); @@ -705,12 +728,13 @@ FilterResult* ModuleFilter::FilterMatch(User* user, const std::string &text, int return NULL; } -bool ModuleFilter::DeleteFilter(const std::string &freeform) +bool ModuleFilter::DeleteFilter(const std::string& freeform, std::string& reason) { for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++) { if (i->freeform == freeform) { + reason.assign(i->reason); delete i->regex; filters.erase(i); return true; @@ -719,7 +743,7 @@ bool ModuleFilter::DeleteFilter(const std::string &freeform) return false; } -std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flgs) +std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform, FilterAction type, const std::string& reason, unsigned long duration, const std::string& flgs, bool config) { for (std::vector<FilterResult>::iterator i = filters.begin(); i != filters.end(); i++) { @@ -731,7 +755,7 @@ std::pair<bool, std::string> ModuleFilter::AddFilter(const std::string& freeform try { - filters.push_back(FilterResult(RegexEngine, freeform, reason, type, duration, flgs, false)); + filters.push_back(FilterResult(RegexEngine, freeform, reason, type, duration, flgs, config)); } catch (ModuleException &e) { @@ -782,11 +806,13 @@ std::string ModuleFilter::FilterActionToString(FilterAction fa) void ModuleFilter::ReadFilters() { + insp::flat_set<std::string> removedfilters; + for (std::vector<FilterResult>::iterator filter = filters.begin(); filter != filters.end(); ) { if (filter->from_config) { - ServerInstance->SNO.WriteGlobalSno('f', "FILTER: removing filter '" + filter->freeform + "' due to config rehash."); + removedfilters.insert(filter->freeform); delete filter->regex; filter = filters.erase(filter); continue; @@ -811,15 +837,17 @@ void ModuleFilter::ReadFilters() if (!StringToFilterAction(action, fa)) fa = FA_NONE; - try - { - filters.push_back(FilterResult(RegexEngine, pattern, reason, fa, duration, flgs, true)); - ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Regular expression %s loaded.", pattern.c_str()); - } - catch (ModuleException &e) - { - ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Error in regular expression '%s': %s", pattern.c_str(), e.GetReason().c_str()); - } + std::pair<bool, std::string> result = static_cast<ModuleFilter*>(this)->AddFilter(pattern, fa, reason, duration, flgs, true); + if (result.first) + removedfilters.erase(pattern); + else + ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Filter '%s' could not be added: %s", pattern.c_str(), result.second.c_str()); + } + + if (!removedfilters.empty()) + { + for (insp::flat_set<std::string>::const_iterator it = removedfilters.begin(); it != removedfilters.end(); ++it) + ServerInstance->SNO.WriteGlobalSno('f', "Removing filter '" + *(it) + "' due to config rehash."); } } diff --git a/src/modules/m_globalload.cpp b/src/modules/m_globalload.cpp index fa0b58a3b..344ac1e66 100644 --- a/src/modules/m_globalload.cpp +++ b/src/modules/m_globalload.cpp @@ -32,7 +32,7 @@ class CommandGloadmodule : public Command CommandGloadmodule(Module* Creator) : Command(Creator,"GLOADMODULE", 1) { flags_needed = 'o'; - syntax = "<modulename> [servermask]"; + syntax = "<modulename> [<servermask>]"; } CmdResult Handle(User* user, const Params& parameters) override @@ -71,7 +71,7 @@ class CommandGunloadmodule : public Command CommandGunloadmodule(Module* Creator) : Command(Creator,"GUNLOADMODULE", 1) { flags_needed = 'o'; - syntax = "<modulename> [servermask]"; + syntax = "<modulename> [<servermask>]"; } CmdResult Handle(User* user, const Params& parameters) override @@ -121,7 +121,7 @@ class CommandGreloadmodule : public Command public: CommandGreloadmodule(Module* Creator) : Command(Creator, "GRELOADMODULE", 1) { - flags_needed = 'o'; syntax = "<modulename> [servermask]"; + flags_needed = 'o'; syntax = "<modulename> [<servermask>]"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_globops.cpp b/src/modules/m_globops.cpp index 56272a11e..4a57a14f6 100644 --- a/src/modules/m_globops.cpp +++ b/src/modules/m_globops.cpp @@ -30,7 +30,7 @@ class CommandGlobops : public Command public: CommandGlobops(Module* Creator) : Command(Creator,"GLOBOPS", 1,1) { - flags_needed = 'o'; syntax = "<any-text>"; + flags_needed = 'o'; syntax = ":<message>"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_hideoper.cpp b/src/modules/m_hideoper.cpp index 792389843..5ac2e6f1e 100644 --- a/src/modules/m_hideoper.cpp +++ b/src/modules/m_hideoper.cpp @@ -123,22 +123,9 @@ class ModuleHideOper if (request.flags['o']) return MOD_RES_DENY; - size_t flag_index = 5; - if (request.whox) - { - // We only need to fiddle with the flags if they are present. - if (!request.whox_fields['f']) - return MOD_RES_PASSTHRU; - - // WHOX makes this a bit tricky as we need to work out the parameter which the flags are in. - flag_index = 0; - static const char* flags = "tcuihsn"; - for (size_t i = 0; i < strlen(flags); ++i) - { - if (request.whox_fields[flags[i]]) - flag_index += 1; - } - } + size_t flag_index; + if (!request.GetFieldIndex('f', flag_index)) + return MOD_RES_PASSTHRU; // hide the "*" that marks the user as an oper from the /WHO line // #chan ident localhost insp22.test nick H@ :0 Attila diff --git a/src/modules/m_httpd.cpp b/src/modules/m_httpd.cpp index 459fb6f5e..7164da8a7 100644 --- a/src/modules/m_httpd.cpp +++ b/src/modules/m_httpd.cpp @@ -29,7 +29,9 @@ #include "modules/httpd.h" // Fix warnings about shadowing in http_parser. -#pragma GCC diagnostic ignored "-Wshadow" +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wshadow" +#endif #include <http_parser.c> @@ -211,24 +213,12 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru AddToCull(); } - const char* Response(unsigned int response) - { - switch (response) - { -#define HTTP_STATUS_CASE(n, m, s) case n: return #s; - HTTP_STATUS_MAP(HTTP_STATUS_CASE) - default: - return "WTF"; - break; - } - } - void SendHTTPError(unsigned int response) { HTTPHeaders empty; std::string data = InspIRCd::Format( "<html><head></head><body>Server error %u: %s<br>" - "<small>Powered by <a href='http://www.inspircd.org'>InspIRCd</a></small></body></html>", response, Response(response)); + "<small>Powered by <a href='https://www.inspircd.org'>InspIRCd</a></small></body></html>", response, http_status_str((http_status)response)); SendHeaders(data.length(), response, empty); WriteData(data); @@ -237,7 +227,7 @@ class HttpServerSocket : public BufferedSocket, public Timer, public insp::intru void SendHeaders(unsigned long size, unsigned int response, HTTPHeaders &rheaders) { - WriteData(InspIRCd::Format("HTTP/%u.%u %u %s\r\n", parser.http_major ? parser.http_major : 1, parser.http_major ? parser.http_minor : 1, response, Response(response))); + WriteData(InspIRCd::Format("HTTP/%u.%u %u %s\r\n", parser.http_major ? parser.http_major : 1, parser.http_major ? parser.http_minor : 1, response, http_status_str((http_status)response))); rheaders.CreateHeader("Date", InspIRCd::TimeString(ServerInstance->Time(), "%a, %d %b %Y %H:%M:%S GMT", true)); rheaders.CreateHeader("Server", INSPIRCD_BRANCH); diff --git a/src/modules/m_ircv3_chghost.cpp b/src/modules/m_ircv3_chghost.cpp index 31e2c1519..dba1b5466 100644 --- a/src/modules/m_ircv3_chghost.cpp +++ b/src/modules/m_ircv3_chghost.cpp @@ -32,7 +32,7 @@ class ModuleIRCv3ChgHost : public Module msg.PushParamRef(ident); msg.PushParamRef(host); ClientProtocol::Event protoev(protoevprov, msg); - IRCv3::WriteNeighborsWithCap(user, protoev, cap); + IRCv3::WriteNeighborsWithCap(user, protoev, cap, true); } public: diff --git a/src/modules/m_ircv3_ctctags.cpp b/src/modules/m_ircv3_ctctags.cpp new file mode 100644 index 000000000..bdf60cf7c --- /dev/null +++ b/src/modules/m_ircv3_ctctags.cpp @@ -0,0 +1,347 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2019 Peter Powell <petpow@saberuk.com> + * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.com> + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "inspircd.h" +#include "modules/cap.h" +#include "modules/ctctags.h" + +class CommandTagMsg : public Command +{ + private: + Cap::Capability& cap; + ChanModeReference moderatedmode; + ChanModeReference noextmsgmode; + Events::ModuleEventProvider tagevprov; + ClientProtocol::EventProvider msgevprov; + + bool FirePreEvents(User* source, MessageTarget& msgtarget, CTCTags::TagMessageDetails& msgdetails) + { + // Inform modules that a TAGMSG wants to be sent. + ModResult modres; + FIRST_MOD_RESULT_CUSTOM(tagevprov, CTCTags::EventListener, OnUserPreTagMessage, modres, (source, msgtarget, msgdetails)); + if (modres == MOD_RES_DENY) + { + // Inform modules that a module blocked the TAGMSG. + FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserTagMessageBlocked, (source, msgtarget, msgdetails)); + return false; + } + + // Inform modules that a TAGMSG is about to be sent. + FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserTagMessage, (source, msgtarget, msgdetails)); + return true; + } + + CmdResult FirePostEvent(User* source, const MessageTarget& msgtarget, const CTCTags::TagMessageDetails& msgdetails) + { + // If the source is local then update its idle time. + LocalUser* lsource = IS_LOCAL(source); + if (lsource) + lsource->idle_lastmsg = ServerInstance->Time(); + + // Inform modules that a TAGMSG was sent. + FOREACH_MOD_CUSTOM(tagevprov, CTCTags::EventListener, OnUserPostTagMessage, (source, msgtarget, msgdetails)); + return CMD_SUCCESS; + } + + CmdResult HandleChannelTarget(User* source, const Params& parameters, const char* target, PrefixMode* pm) + { + Channel* chan = ServerInstance->FindChan(target); + if (!chan) + { + // The target channel does not exist. + source->WriteNumeric(Numerics::NoSuchChannel(parameters[0])); + return CMD_FAILURE; + } + + if (IS_LOCAL(source)) + { + if (chan->IsModeSet(noextmsgmode) && !chan->HasUser(source)) + { + // The noextmsg mode is set and the source is not in the channel. + source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (no external messages)"); + return CMD_FAILURE; + } + + bool no_chan_priv = chan->GetPrefixValue(source) < VOICE_VALUE; + if (no_chan_priv && chan->IsModeSet(moderatedmode)) + { + // The moderated mode is set and the source has no status rank. + source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (+m)"); + return CMD_FAILURE; + } + + if (no_chan_priv && ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL && chan->IsBanned(source)) + { + // The source is banned in the channel and restrictbannedusers is enabled. + if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY) + source->WriteNumeric(ERR_CANNOTSENDTOCHAN, chan->name, "Cannot send to channel (you're banned)"); + return CMD_FAILURE; + } + } + + // Fire the pre-message events. + MessageTarget msgtarget(chan, pm ? pm->GetPrefix() : 0); + CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); + if (!FirePreEvents(source, msgtarget, msgdetails)) + return CMD_FAILURE; + + unsigned int minrank = pm ? pm->GetPrefixRank() : 0; + CTCTags::TagMessage message(source, chan, parameters.GetTags()); + const Channel::MemberMap& userlist = chan->GetUsers(); + for (Channel::MemberMap::const_iterator iter = userlist.begin(); iter != userlist.end(); ++iter) + { + LocalUser* luser = IS_LOCAL(iter->first); + + // Don't send to remote users or the user who is the source. + if (!luser || luser == source) + continue; + + // Don't send to unprivileged or exempt users. + if (iter->second->getRank() < minrank || msgdetails.exemptions.count(luser)) + continue; + + // Send to users if they have the capability. + if (cap.get(luser)) + luser->Send(msgevprov, message); + } + return FirePostEvent(source, msgtarget, msgdetails); + } + + CmdResult HandleServerTarget(User* source, const Params& parameters) + { + // If the source isn't allowed to mass message users then reject + // the attempt to mass-message users. + if (!source->HasPrivPermission("users/mass-message")) + return CMD_FAILURE; + + // Extract the server glob match from the target parameter. + std::string servername(parameters[0], 1); + + // Fire the pre-message events. + MessageTarget msgtarget(&servername); + CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); + if (!FirePreEvents(source, msgtarget, msgdetails)) + return CMD_FAILURE; + + // If the current server name matches the server name glob then send + // the message out to the local users. + if (InspIRCd::Match(ServerInstance->Config->ServerName, servername)) + { + CTCTags::TagMessage message(source, "$*", parameters.GetTags()); + const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers(); + for (UserManager::LocalList::const_iterator iter = list.begin(); iter != list.end(); ++iter) + { + LocalUser* luser = IS_LOCAL(*iter); + + // Don't send to unregistered users or the user who is the source. + if (luser->registered != REG_ALL || luser == source) + continue; + + // Don't send to exempt users. + if (msgdetails.exemptions.count(luser)) + continue; + + // Send to users if they have the capability. + if (cap.get(luser)) + luser->Send(msgevprov, message); + } + } + + // Fire the post-message event. + return FirePostEvent(source, msgtarget, msgdetails); + } + + CmdResult HandleUserTarget(User* source, const Params& parameters) + { + User* target; + if (IS_LOCAL(source)) + { + // Local sources can specify either a nick or a nick@server mask as the target. + const char* targetserver = strchr(parameters[0].c_str(), '@'); + if (targetserver) + { + // The target is a user on a specific server (e.g. jto@tolsun.oulu.fi). + target = ServerInstance->FindNickOnly(parameters[0].substr(0, targetserver - parameters[0].c_str())); + if (target && strcasecmp(target->server->GetName().c_str(), targetserver + 1)) + target = NULL; + } + else + { + // If the source is a local user then we only look up the target by nick. + target = ServerInstance->FindNickOnly(parameters[0]); + } + } + else + { + // Remote users can only specify a nick or UUID as the target. + target = ServerInstance->FindNick(parameters[0]); + } + + if (!target || target->registered != REG_ALL) + { + // The target user does not exist or is not fully registered. + source->WriteNumeric(Numerics::NoSuchNick(parameters[0])); + return CMD_FAILURE; + } + + // Fire the pre-message events. + MessageTarget msgtarget(target); + CTCTags::TagMessageDetails msgdetails(parameters.GetTags()); + if (!FirePreEvents(source, msgtarget, msgdetails)) + return CMD_FAILURE; + + LocalUser* const localtarget = IS_LOCAL(target); + if (localtarget && cap.get(localtarget)) + { + // Send to the target if they have the capability and are a local user. + CTCTags::TagMessage message(source, localtarget, parameters.GetTags()); + localtarget->Send(msgevprov, message); + } + + // Fire the post-message event. + return FirePostEvent(source, msgtarget, msgdetails); + } + + public: + CommandTagMsg(Module* Creator, Cap::Capability& Cap) + : Command(Creator, "TAGMSG", 1) + , cap(Cap) + , moderatedmode(Creator, "moderated") + , noextmsgmode(Creator, "noextmsg") + , tagevprov(Creator, "event/tagmsg") + , msgevprov(Creator, "TAGMSG") + { + allow_empty_last_param = false; + } + + CmdResult Handle(User* user, const Params& parameters) override + { + if (CommandParser::LoopCall(user, this, parameters, 0)) + return CMD_SUCCESS; + + // Check that the source has the message tags capability. + if (IS_LOCAL(user) && !cap.get(user)) + return CMD_FAILURE; + + // The target is a server glob. + if (parameters[0][0] == '$') + return HandleServerTarget(user, parameters); + + // If the message begins with a status character then look it up. + const char* target = parameters[0].c_str(); + PrefixMode* pmh = ServerInstance->Modes.FindPrefix(target[0]); + if (pmh) + target++; + + // The target is a channel name. + if (*target == '#') + return HandleChannelTarget(user, parameters, target, pmh); + + // The target is a nickname. + return HandleUserTarget(user, parameters); + } + + RouteDescriptor GetRouting(User* user, const Params& parameters) override + { + return ROUTE_MESSAGE(parameters[0]); + } +}; + +class C2CTags : public ClientProtocol::MessageTagProvider +{ + private: + Cap::Capability& cap; + + public: + C2CTags(Module* Creator, Cap::Capability& Cap) + : ClientProtocol::MessageTagProvider(Creator) + , cap(Cap) + { + } + + ModResult OnProcessTag(User* user, const std::string& tagname, std::string& tagvalue) override + { + // A client-only tag is prefixed with a plus sign (+) and otherwise conforms + // to the format specified in IRCv3.2 tags. + if (tagname[0] != '+' || tagname.length() < 2) + return MOD_RES_PASSTHRU; + + // If the user is local then we check whether they have the message-tags cap + // enabled. If not then we reject all client-only tags originating from them. + LocalUser* lu = IS_LOCAL(user); + if (lu && !cap.get(lu)) + return MOD_RES_DENY; + + // Remote users have their client-only tags checked by their local server. + return MOD_RES_ALLOW; + } + + bool ShouldSendTag(LocalUser* user, const ClientProtocol::MessageTagData& tagdata) override + { + return cap.get(user); + } +}; + +class ModuleIRCv3CTCTags + : public Module + , public CTCTags::EventListener +{ + private: + Cap::Capability cap; + CommandTagMsg cmd; + C2CTags c2ctags; + + ModResult CopyClientTags(const ClientProtocol::TagMap& tags_in, ClientProtocol::TagMap& tags_out) + { + for (ClientProtocol::TagMap::const_iterator i = tags_in.begin(); i != tags_in.end(); ++i) + { + const ClientProtocol::MessageTagData& tagdata = i->second; + if (tagdata.tagprov == &c2ctags) + tags_out.insert(*i); + } + return MOD_RES_PASSTHRU; + } + + public: + ModuleIRCv3CTCTags() + : CTCTags::EventListener(this) + , cap(this, "message-tags") + , cmd(this, cap) + , c2ctags(this, cap) + { + } + + ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) override + { + return CopyClientTags(details.tags_in, details.tags_out); + } + + ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) override + { + return CopyClientTags(details.tags_in, details.tags_out); + } + + Version GetVersion() override + { + return Version("Provides the DRAFT message-tags IRCv3 extension", VF_VENDOR | VF_COMMON); + } +}; + +MODULE_INIT(ModuleIRCv3CTCTags) diff --git a/src/modules/m_ircv3_echomessage.cpp b/src/modules/m_ircv3_echomessage.cpp index 16d6751d9..1a08ef3d9 100644 --- a/src/modules/m_ircv3_echomessage.cpp +++ b/src/modules/m_ircv3_echomessage.cpp @@ -20,14 +20,21 @@ #include "inspircd.h" #include "modules/cap.h" +#include "modules/ctctags.h" -class ModuleIRCv3EchoMessage : public Module +class ModuleIRCv3EchoMessage + : public Module + , public CTCTags::EventListener { + private: Cap::Capability cap; + ClientProtocol::EventProvider tagmsgprov; public: ModuleIRCv3EchoMessage() - : cap(this, "echo-message") + : CTCTags::EventListener(this) + , cap(this, "echo-message") + , tagmsgprov(this, "TAGMSG") { } @@ -64,6 +71,35 @@ class ModuleIRCv3EchoMessage : public Module } } + void OnUserPostTagMessage(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) override + { + if (!cap.get(user) || !details.echo) + return; + + // Caps are only set on local users + LocalUser* const localuser = static_cast<LocalUser*>(user); + + const ClientProtocol::TagMap& tags = details.echo_original ? details.tags_in : details.tags_out; + if (target.type == MessageTarget::TYPE_USER) + { + User* destuser = target.Get<User>(); + CTCTags::TagMessage message(user, destuser, tags); + localuser->Send(tagmsgprov, message); + } + else if (target.type == MessageTarget::TYPE_CHANNEL) + { + Channel* chan = target.Get<Channel>(); + CTCTags::TagMessage message(user, chan, tags); + localuser->Send(tagmsgprov, message); + } + else + { + const std::string* servername = target.Get<std::string>(); + CTCTags::TagMessage message(user, servername->c_str(), tags); + localuser->Send(tagmsgprov, message); + } + } + void OnUserMessageBlocked(User* user, const MessageTarget& target, const MessageDetails& details) override { // Prevent spammers from knowing that their spam was blocked. @@ -71,6 +107,13 @@ class ModuleIRCv3EchoMessage : public Module OnUserPostMessage(user, target, details); } + void OnUserTagMessageBlocked(User* user, const MessageTarget& target, const CTCTags::TagMessageDetails& details) override + { + // Prevent spammers from knowing that their spam was blocked. + if (details.echo_original) + OnUserPostTagMessage(user, target, details); + } + Version GetVersion() override { return Version("Provides the echo-message IRCv3 extension", VF_VENDOR); diff --git a/src/modules/m_knock.cpp b/src/modules/m_knock.cpp index 5d76a9d66..b2824c78e 100644 --- a/src/modules/m_knock.cpp +++ b/src/modules/m_knock.cpp @@ -46,7 +46,7 @@ class CommandKnock : public Command , noknockmode(Noknockmode) , inviteonlymode(Creator, "inviteonly") { - syntax = "<channel> <reason>"; + syntax = "<channel> :<reason>"; Penalty = 5; } diff --git a/src/modules/m_modenotice.cpp b/src/modules/m_modenotice.cpp index 4a94c89ee..5376d4cc4 100644 --- a/src/modules/m_modenotice.cpp +++ b/src/modules/m_modenotice.cpp @@ -24,7 +24,7 @@ class CommandModeNotice : public Command public: CommandModeNotice(Module* parent) : Command(parent,"MODENOTICE",2,2) { - syntax = "<modes> <message>"; + syntax = "<modeletters> :<message>"; flags_needed = 'o'; } diff --git a/src/modules/m_monitor.cpp b/src/modules/m_monitor.cpp index 4225d5fb2..809a7fb24 100644 --- a/src/modules/m_monitor.cpp +++ b/src/modules/m_monitor.cpp @@ -316,7 +316,7 @@ class CommandMonitor : public SplitCommand { Penalty = 2; allow_empty_last_param = false; - syntax = "[C|L|S|+ <nick1>[,<nick2>]|- <nick1>[,<nick2>]"; + syntax = "C|L|S|(+|-) <nick>[,<nick>]+"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) override diff --git a/src/modules/m_namedmodes.cpp b/src/modules/m_namedmodes.cpp index c99ff9133..81afb6cac 100644 --- a/src/modules/m_namedmodes.cpp +++ b/src/modules/m_namedmodes.cpp @@ -56,7 +56,7 @@ class CommandProp : public SplitCommand CommandProp(Module* parent) : SplitCommand(parent, "PROP", 1) { - syntax = "<user|channel> {[+-]<mode> [<value>]}*"; + syntax = "<channel> [[(+|-)]<mode> [<value>]]"; } CmdResult HandleLocal(LocalUser* src, const Params& parameters) override diff --git a/src/modules/m_namesx.cpp b/src/modules/m_namesx.cpp index 5d265fc56..549b0755e 100644 --- a/src/modules/m_namesx.cpp +++ b/src/modules/m_namesx.cpp @@ -84,22 +84,9 @@ class ModuleNamesX if (prefixes.length() <= 1) return MOD_RES_PASSTHRU; - size_t flag_index = 5; - if (request.whox) - { - // We only need to fiddle with the flags if they are present. - if (!request.whox_fields['f']) - return MOD_RES_PASSTHRU; - - // WHOX makes this a bit tricky as we need to work out the parameter which the flags are in. - flag_index = 0; - static const char* flags = "tcuihsn"; - for (size_t i = 0; i < strlen(flags); ++i) - { - if (request.whox_fields[flags[i]]) - flag_index += 1; - } - } + size_t flag_index; + if (!request.GetFieldIndex('f', flag_index)) + return MOD_RES_PASSTHRU; // #chan ident localhost insp22.test nick H@ :0 Attila if (numeric.GetParams().size() <= flag_index) diff --git a/src/modules/m_nationalchars.cpp b/src/modules/m_nationalchars.cpp index 0302cb7f5..884efed23 100644 --- a/src/modules/m_nationalchars.cpp +++ b/src/modules/m_nationalchars.cpp @@ -20,8 +20,8 @@ */ -/* Contains a code of Unreal IRCd + Bynets patch ( http://www.unrealircd.com/ and http://www.bynets.org/ ) - Original patch is made by Dmitry "Killer{R}" Kononko. ( http://killprog.com/ ) +/* Contains a code of Unreal IRCd + Bynets patch (https://www.unrealircd.org and https://bynets.org) + Original patch is made by Dmitry "Killer{R}" Kononko. (http://killprog.com) Changed at 2008-06-15 - 2009-02-11 by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru */ diff --git a/src/modules/m_nicklock.cpp b/src/modules/m_nicklock.cpp index 987dea86d..77cc53359 100644 --- a/src/modules/m_nicklock.cpp +++ b/src/modules/m_nicklock.cpp @@ -40,7 +40,7 @@ class CommandNicklock : public Command locked(ext) { flags_needed = 'o'; - syntax = "<oldnick> <newnick>"; + syntax = "<nick> <newnick>"; translation = { TR_NICK, TR_TEXT }; } @@ -100,7 +100,7 @@ class CommandNickunlock : public Command locked(ext) { flags_needed = 'o'; - syntax = "<locked-nick>"; + syntax = "<nick>"; translation = { TR_NICK }; } diff --git a/src/modules/m_noctcp.cpp b/src/modules/m_noctcp.cpp index b7e981450..9c27b20ea 100644 --- a/src/modules/m_noctcp.cpp +++ b/src/modules/m_noctcp.cpp @@ -52,6 +52,9 @@ class ModuleNoCTCP : public Module if (target.type == MessageTarget::TYPE_CHANNEL) { + if (user->HasPrivPermission("channels/ignore-noctcp")) + return MOD_RES_PASSTHRU; + Channel* c = target.Get<Channel>(); ModResult res = CheckExemption::Call(exemptionprov, user, c, "noctcp"); if (res == MOD_RES_ALLOW) @@ -65,11 +68,14 @@ class ModuleNoCTCP : public Module } else if (target.type == MessageTarget::TYPE_USER) { + if (user->HasPrivPermission("users/ignore-noctcp")) + return MOD_RES_PASSTHRU; + User* u = target.Get<User>(); if (u->IsModeSet(ncu)) { user->WriteNumeric(ERR_CANTSENDTOUSER, u->nick, "Can't send CTCP to user (+T set)"); - return MOD_RES_PASSTHRU; + return MOD_RES_DENY; } } return MOD_RES_PASSTHRU; diff --git a/src/modules/m_password_hash.cpp b/src/modules/m_password_hash.cpp index f0a12019b..ce0e1e156 100644 --- a/src/modules/m_password_hash.cpp +++ b/src/modules/m_password_hash.cpp @@ -28,7 +28,7 @@ class CommandMkpasswd : public Command public: CommandMkpasswd(Module* Creator) : Command(Creator, "MKPASSWD", 2) { - syntax = "<hashtype> <any-text>"; + syntax = "<hashtype> <plaintext>"; Penalty = 5; } diff --git a/src/modules/m_permchannels.cpp b/src/modules/m_permchannels.cpp index 59695a43a..90215fdf2 100644 --- a/src/modules/m_permchannels.cpp +++ b/src/modules/m_permchannels.cpp @@ -193,9 +193,9 @@ public: std::string channel = tag->getString("channel"); std::string modes = tag->getString("modes"); - if ((channel.empty()) || (channel.length() > ServerInstance->Config->Limits.ChanMax)) + if (!ServerInstance->IsChannel(channel)) { - ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Ignoring permchannels tag with empty or too long channel name (\"" + channel + "\")"); + ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Ignoring permchannels tag with invalid channel name (\"" + channel + "\")"); continue; } diff --git a/src/modules/m_remove.cpp b/src/modules/m_remove.cpp index eca43ff1c..6459b898d 100644 --- a/src/modules/m_remove.cpp +++ b/src/modules/m_remove.cpp @@ -165,7 +165,7 @@ class CommandRemove : public RemoveBase CommandRemove(Module* Creator, bool& snk, ChanModeReference& nkm) : RemoveBase(Creator, snk, nkm, "REMOVE") { - syntax = "<channel> <nick> [<reason>]"; + syntax = "<channel> <nick> [:<reason>]"; translation = { TR_NICK, TR_TEXT, TR_TEXT }; } @@ -183,7 +183,7 @@ class CommandFpart : public RemoveBase CommandFpart(Module* Creator, bool& snk, ChanModeReference& nkm) : RemoveBase(Creator, snk, nkm, "FPART") { - syntax = "<channel> <nick> [<reason>]"; + syntax = "<channel> <nick> [:<reason>]"; translation = { TR_TEXT, TR_NICK, TR_TEXT }; } diff --git a/src/modules/m_repeat.cpp b/src/modules/m_repeat.cpp index 0c93075f5..7f7fa56c6 100644 --- a/src/modules/m_repeat.cpp +++ b/src/modules/m_repeat.cpp @@ -141,14 +141,14 @@ class RepeatMode : public ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> > if (!ParseSettings(source, parameter, settings)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, - "Invalid repeat syntax. Syntax is {[~*]}[lines]:[time]{:[difference]}{:[backlog]}.")); + "Invalid repeat syntax. Syntax is: [~|*]<lines>:<sec>[:<difference>][:<backlog>]")); return MODEACTION_DENY; } if ((settings.Backlog > 0) && (settings.Lines > settings.Backlog)) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, - "Invalid repeat syntax. You can't set needed lines higher than backlog.")); + "Invalid repeat syntax. You can't set lines higher than backlog.")); return MODEACTION_DENY; } @@ -319,7 +319,7 @@ class RepeatMode : public ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> > if (ms.MaxSecs && settings.Seconds > ms.MaxSecs) { source->WriteNumeric(Numerics::InvalidModeParameter(channel, this, parameter, InspIRCd::Format( - "Invalid repeat parameter. The seconds you specified is too great. Maximum allowed is %u.", ms.MaxSecs))); + "Invalid repeat parameter. The seconds you specified are too great. Maximum allowed is %u.", ms.MaxSecs))); return false; } diff --git a/src/modules/m_rline.cpp b/src/modules/m_rline.cpp index a8bf98e3b..6c4db08a9 100644 --- a/src/modules/m_rline.cpp +++ b/src/modules/m_rline.cpp @@ -80,9 +80,9 @@ class RLine : public XLine ZLine* zl = new ZLine(ServerInstance->Time(), duration ? expiry - ServerInstance->Time() : 0, ServerInstance->Config->ServerName.c_str(), reason.c_str(), u->GetIPString()); if (ServerInstance->XLines->AddLine(zl, NULL)) { - std::string timestr = InspIRCd::TimeString(zl->expiry); - ServerInstance->SNO.WriteToSnoMask('x', "Z-line added due to R-line match on %s%s%s: %s", - zl->ipaddr.c_str(), zl->duration ? " to expire on " : "", zl->duration ? timestr.c_str() : "", zl->reason.c_str()); + std::string expirystr = zl->duration ? InspIRCd::Format(" to expire in %s (on %s)", InspIRCd::DurationString(zl->duration).c_str(), InspIRCd::TimeString(zl->expiry).c_str()) : ""; + ServerInstance->SNO.WriteToSnoMask('x', "Z-line added due to R-line match on %s%s: %s", + zl->ipaddr.c_str(), expirystr.c_str(), zl->reason.c_str()); added_zline = true; } else @@ -137,7 +137,7 @@ class CommandRLine : public Command public: CommandRLine(Module* Creator, RLineFactory& rlf) : Command(Creator,"RLINE", 1, 3), factory(rlf) { - flags_needed = 'o'; this->syntax = "<regex> [<rline-duration>] :<reason>"; + flags_needed = 'o'; this->syntax = "<regex> [<duration> :<reason>]"; } CmdResult Handle(User* user, const Params& parameters) override @@ -174,9 +174,9 @@ class CommandRLine : public Command } else { - time_t c_requires_crap = duration + ServerInstance->Time(); - std::string timestr = InspIRCd::TimeString(c_requires_crap); - ServerInstance->SNO.WriteToSnoMask('x', "%s added timed R-line for %s to expire on %s: %s", user->nick.c_str(), parameters[0].c_str(), timestr.c_str(), parameters[2].c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added timed R-line for %s to expire in %s (on %s): %s", + user->nick.c_str(), parameters[0].c_str(), InspIRCd::DurationString(duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), parameters[2].c_str()); } ServerInstance->XLines->ApplyLines(); diff --git a/src/modules/m_rmode.cpp b/src/modules/m_rmode.cpp index 76b89d6db..fdeb8565d 100644 --- a/src/modules/m_rmode.cpp +++ b/src/modules/m_rmode.cpp @@ -28,7 +28,7 @@ class CommandRMode : public Command CommandRMode(Module* Creator) : Command(Creator,"RMODE", 2, 3) { allow_empty_last_param = false; - syntax = "<channel> <mode> [pattern]"; + syntax = "<channel> <mode> [<pattern>]"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_sajoin.cpp b/src/modules/m_sajoin.cpp index 2ed66f9fd..8d7403b0e 100644 --- a/src/modules/m_sajoin.cpp +++ b/src/modules/m_sajoin.cpp @@ -29,7 +29,8 @@ class CommandSajoin : public Command CommandSajoin(Module* Creator) : Command(Creator,"SAJOIN", 1) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = "[<nick>] <channel>[,<channel>]"; + flags_needed = 'o'; + syntax = "[<nick>] <channel>[,<channel>]+"; translation = { TR_NICK, TR_TEXT }; } @@ -53,7 +54,7 @@ class CommandSajoin : public Command if (dest->server->IsULine()) { - user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client"); + user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } if (IS_LOCAL(user) && !ServerInstance->IsChannel(channel)) diff --git a/src/modules/m_sakick.cpp b/src/modules/m_sakick.cpp index af336ed8d..7f1144504 100644 --- a/src/modules/m_sakick.cpp +++ b/src/modules/m_sakick.cpp @@ -27,7 +27,7 @@ class CommandSakick : public Command public: CommandSakick(Module* Creator) : Command(Creator,"SAKICK", 2, 3) { - flags_needed = 'o'; syntax = "<channel> <nick> [reason]"; + flags_needed = 'o'; syntax = "<channel> <nick> [:<reason>]"; translation = { TR_TEXT, TR_NICK, TR_TEXT }; } @@ -42,7 +42,7 @@ class CommandSakick : public Command if (dest->server->IsULine()) { - user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client"); + user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp index 3e823b09f..6df95c10e 100644 --- a/src/modules/m_samode.cpp +++ b/src/modules/m_samode.cpp @@ -33,7 +33,7 @@ class CommandSamode : public Command CommandSamode(Module* Creator) : Command(Creator,"SAMODE", 2) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = "<target> <modes> {<mode-parameters>}"; + flags_needed = 'o'; syntax = "<target> (+|-)<modes> [<mode-parameters>]"; active = false; } diff --git a/src/modules/m_sanick.cpp b/src/modules/m_sanick.cpp index 3d809f5d4..0e785359e 100644 --- a/src/modules/m_sanick.cpp +++ b/src/modules/m_sanick.cpp @@ -29,7 +29,8 @@ class CommandSanick : public Command CommandSanick(Module* Creator) : Command(Creator,"SANICK", 2) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = "<nick> <new-nick>"; + flags_needed = 'o'; + syntax = "<nick> <newnick>"; translation = { TR_NICK, TR_TEXT }; } @@ -42,7 +43,7 @@ class CommandSanick : public Command { if (target && target->server->IsULine()) { - user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client"); + user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } diff --git a/src/modules/m_sapart.cpp b/src/modules/m_sapart.cpp index 484bb44e3..57cc70628 100644 --- a/src/modules/m_sapart.cpp +++ b/src/modules/m_sapart.cpp @@ -28,7 +28,8 @@ class CommandSapart : public Command public: CommandSapart(Module* Creator) : Command(Creator,"SAPART", 2, 3) { - flags_needed = 'o'; syntax = "<nick> <channel>[,<channel>] [reason]"; + flags_needed = 'o'; + syntax = "<nick> <channel>[,<channel>]+ [:<reason>]"; translation = { TR_NICK, TR_TEXT, TR_TEXT }; } @@ -48,7 +49,7 @@ class CommandSapart : public Command if (dest->server->IsULine()) { - user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client"); + user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } diff --git a/src/modules/m_saquit.cpp b/src/modules/m_saquit.cpp index 6b9af2baf..1d03d1fc7 100644 --- a/src/modules/m_saquit.cpp +++ b/src/modules/m_saquit.cpp @@ -28,7 +28,8 @@ class CommandSaquit : public Command public: CommandSaquit(Module* Creator) : Command(Creator, "SAQUIT", 2, 2) { - flags_needed = 'o'; syntax = "<nick> <reason>"; + flags_needed = 'o'; + syntax = "<nick> :<reason>"; translation = { TR_NICK, TR_TEXT }; } @@ -39,7 +40,7 @@ class CommandSaquit : public Command { if (dest->server->IsULine()) { - user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a u-lined client"); + user->WriteNumeric(ERR_NOPRIVILEGES, "Cannot use an SA command on a U-lined client"); return CMD_FAILURE; } diff --git a/src/modules/m_satopic.cpp b/src/modules/m_satopic.cpp index f2c75942e..4f5efde3b 100644 --- a/src/modules/m_satopic.cpp +++ b/src/modules/m_satopic.cpp @@ -26,7 +26,7 @@ class CommandSATopic : public Command public: CommandSATopic(Module* Creator) : Command(Creator,"SATOPIC", 2, 2) { - flags_needed = 'o'; syntax = "<target> <topic>"; + flags_needed = 'o'; syntax = "<channel> :<topic>"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_sethost.cpp b/src/modules/m_sethost.cpp index 4b22cae66..58d712c70 100644 --- a/src/modules/m_sethost.cpp +++ b/src/modules/m_sethost.cpp @@ -32,7 +32,7 @@ class CommandSethost : public Command : Command(Creator,"SETHOST", 1) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = "<new-hostname>"; + flags_needed = 'o'; syntax = "<host>"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_setident.cpp b/src/modules/m_setident.cpp index d83d5a75e..ecfa62bea 100644 --- a/src/modules/m_setident.cpp +++ b/src/modules/m_setident.cpp @@ -30,7 +30,7 @@ class CommandSetident : public Command CommandSetident(Module* Creator) : Command(Creator,"SETIDENT", 1) { allow_empty_last_param = false; - flags_needed = 'o'; syntax = "<new-ident>"; + flags_needed = 'o'; syntax = "<ident>"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_setname.cpp b/src/modules/m_setname.cpp index 135525512..3fedc9830 100644 --- a/src/modules/m_setname.cpp +++ b/src/modules/m_setname.cpp @@ -30,7 +30,7 @@ class CommandSetname : public Command CommandSetname(Module* Creator) : Command(Creator,"SETNAME", 1, 1) { allow_empty_last_param = false; - syntax = "<new real name>"; + syntax = ":<realname>"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_shun.cpp b/src/modules/m_shun.cpp index f8b7f82bb..9e7529571 100644 --- a/src/modules/m_shun.cpp +++ b/src/modules/m_shun.cpp @@ -53,7 +53,7 @@ class CommandShun : public Command public: CommandShun(Module* Creator) : Command(Creator, "SHUN", 1, 3) { - flags_needed = 'o'; this->syntax = "<nick!user@hostmask> [<shun-duration>] :<reason>"; + flags_needed = 'o'; this->syntax = "<nick!user@host> [<duration> :<reason>]"; } CmdResult Handle(User* user, const Params& parameters) override @@ -110,15 +110,14 @@ class CommandShun : public Command { if (!duration) { - ServerInstance->SNO.WriteToSnoMask('x',"%s added permanent SHUN for %s: %s", + ServerInstance->SNO.WriteToSnoMask('x', "%s added permanent SHUN for %s: %s", user->nick.c_str(), target.c_str(), expr.c_str()); } else { - time_t c_requires_crap = duration + ServerInstance->Time(); - std::string timestr = InspIRCd::TimeString(c_requires_crap); - ServerInstance->SNO.WriteToSnoMask('x', "%s added timed SHUN for %s to expire on %s: %s", - user->nick.c_str(), target.c_str(), timestr.c_str(), expr.c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "%s added timed SHUN for %s to expire in %s (on %s): %s", + user->nick.c_str(), target.c_str(), InspIRCd::DurationString(duration).c_str(), + InspIRCd::TimeString(ServerInstance->Time() + duration).c_str(), expr.c_str()); } } else diff --git a/src/modules/m_silence.cpp b/src/modules/m_silence.cpp index 5c4a8c630..40b2bb81f 100644 --- a/src/modules/m_silence.cpp +++ b/src/modules/m_silence.cpp @@ -24,7 +24,7 @@ #include "inspircd.h" /* Improved drop-in replacement for the /SILENCE command - * syntax: /SILENCE [+|-]<mask> <p|c|i|n|t|a|x> as in <privatemessage|channelmessage|invites|privatenotice|channelnotice|all|exclude> + * syntax: /SILENCE [(+|-)<mask> [p|c|i|n|t|a|x]] as in [privatemessages|channelmessages|invites|privatenotices|channelnotices|all|exclude] * * example that blocks all except private messages * /SILENCE +*!*@* a @@ -74,7 +74,7 @@ class CommandSVSSilence : public Command public: CommandSVSSilence(Module* Creator) : Command(Creator,"SVSSILENCE", 2) { - syntax = "<target> {[+|-]<mask> <p|c|i|n|t|a|x>}"; + syntax = "<target> (+|-)<mask> [p|c|i|n|t|a|x]"; translation = { TR_NICK, TR_TEXT, TR_TEXT }; } @@ -119,7 +119,7 @@ class CommandSilence : public Command , ext("silence_list", ExtensionItem::EXT_USER, Creator) { allow_empty_last_param = false; - syntax = "{[+|-]<mask> <p|c|i|n|t|a|x>}"; + syntax = "[(+|-)<mask> [p|c|i|n|t|a|x]]"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_spanningtree/addline.cpp b/src/modules/m_spanningtree/addline.cpp index 85b550508..81e9d1467 100644 --- a/src/modules/m_spanningtree/addline.cpp +++ b/src/modules/m_spanningtree/addline.cpp @@ -50,14 +50,16 @@ CmdResult CommandAddLine::Handle(User* usr, Params& params) { if (xl->duration) { - std::string timestr = InspIRCd::TimeString(xl->expiry); - ServerInstance->SNO.WriteToSnoMask('X',"%s added %s%s on %s to expire on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", - params[1].c_str(), timestr.c_str(), params[5].c_str()); + ServerInstance->SNO.WriteToSnoMask('X', "%s added %s%s on %s to expire in %s (on %s): %s", + setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "", + params[1].c_str(), InspIRCd::DurationString(xl->duration).c_str(), + InspIRCd::TimeString(xl->expiry).c_str(), params[5].c_str()); } else { - ServerInstance->SNO.WriteToSnoMask('X',"%s added permanent %s%s on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", - params[1].c_str(),params[5].c_str()); + ServerInstance->SNO.WriteToSnoMask('X', "%s added permanent %s%s on %s: %s", + setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "", + params[1].c_str(), params[5].c_str()); } TreeServer* remoteserver = TreeServer::Get(usr); diff --git a/src/modules/m_spanningtree/compat.cpp b/src/modules/m_spanningtree/compat.cpp index d95465f40..9ba6cfc1c 100644 --- a/src/modules/m_spanningtree/compat.cpp +++ b/src/modules/m_spanningtree/compat.cpp @@ -42,7 +42,7 @@ void TreeSocket::WriteLine(const std::string& original_line) if (line[0] == '@') { // The line contains tags which the 1202 protocol can't handle. - line.erase(0, a); + line.erase(0, a + 1); a = line.find(' '); } std::string::size_type b = line.find(' ', a + 1); @@ -309,6 +309,11 @@ void TreeSocket::WriteLine(const std::string& original_line) push.append(line, 26, std::string::npos); push.swap(line); } + else if (command == "TAGMSG") + { + // Drop IRCv3 tag messages as v2 has no message tag support. + return; + } } WriteLineNoCompat(line); return; diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 321943e2e..ee73e6d9f 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -45,6 +45,7 @@ ModuleSpanningTree::ModuleSpanningTree() , commands(this) , currmembid(0) , eventprov(this, "event/server") + , sslapi(this) , DNS(this, "DNS") , tagevprov(this, "event/messagetag") , loopCall(false) @@ -447,6 +448,10 @@ void ModuleSpanningTree::OnUserConnect(LocalUser* user) if (user->quitting) return; + // Create the lazy ssl_cert metadata for this user if not already created. + if (sslapi) + sslapi->GetCertificate(user); + CommandUID::Builder(user).Broadcast(); if (user->IsOper()) diff --git a/src/modules/m_spanningtree/main.h b/src/modules/m_spanningtree/main.h index 7ffa4a748..1afd5e7ef 100644 --- a/src/modules/m_spanningtree/main.h +++ b/src/modules/m_spanningtree/main.h @@ -26,6 +26,7 @@ #include "inspircd.h" #include "event.h" #include "modules/dns.h" +#include "modules/ssl.h" #include "modules/stats.h" #include "servercommand.h" #include "commands.h" @@ -80,6 +81,9 @@ class ModuleSpanningTree */ Events::ModuleEventProvider eventprov; + /** API for accessing user SSL certificates. */ + UserCertificateAPI sslapi; + public: dynamic_reference<DNS::Manager> DNS; diff --git a/src/modules/m_spanningtree/rsquit.cpp b/src/modules/m_spanningtree/rsquit.cpp index f4ffe3bfa..22f181f82 100644 --- a/src/modules/m_spanningtree/rsquit.cpp +++ b/src/modules/m_spanningtree/rsquit.cpp @@ -29,7 +29,7 @@ CommandRSQuit::CommandRSQuit(Module* Creator) : Command(Creator, "RSQUIT", 1) { flags_needed = 'o'; - syntax = "<target-server-mask> [reason]"; + syntax = "<target-server-mask> [:<reason>]"; } CmdResult CommandRSQuit::Handle(User* user, const Params& parameters) diff --git a/src/modules/m_spanningtree/server.cpp b/src/modules/m_spanningtree/server.cpp index e2ba99682..9e1b164be 100644 --- a/src/modules/m_spanningtree/server.cpp +++ b/src/modules/m_spanningtree/server.cpp @@ -114,7 +114,7 @@ Link* TreeSocket::AuthRemote(const CommandBase::Params& params) for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i < Utils->LinkBlocks.end(); i++) { Link* x = *i; - if ((!stdalgo::string::equalsci(x->Name, sname)) && (x->Name != "*")) // open link allowance + if (!InspIRCd::Match(sname, x->Name)) continue; if (!ComparePass(*x, password)) diff --git a/src/modules/m_sslinfo.cpp b/src/modules/m_sslinfo.cpp index b6a208d39..1c5c4d8c9 100644 --- a/src/modules/m_sslinfo.cpp +++ b/src/modules/m_sslinfo.cpp @@ -21,6 +21,7 @@ #include "modules/ssl.h" #include "modules/webirc.h" #include "modules/whois.h" +#include "modules/who.h" enum { @@ -184,6 +185,7 @@ class ModuleSSLInfo : public Module , public WebIRC::EventListener , public Whois::EventListener + , public Who::EventListener { private: CommandSSLInfo cmd; @@ -197,6 +199,7 @@ class ModuleSSLInfo ModuleSSLInfo() : WebIRC::EventListener(this) , Whois::EventListener(this) + , Who::EventListener(this) , cmd(this) { } @@ -218,6 +221,19 @@ class ModuleSSLInfo } } + ModResult OnWhoLine(const Who::Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) override + { + size_t flag_index; + if (!request.GetFieldIndex('f', flag_index)) + return MOD_RES_PASSTHRU; + + ssl_cert* cert = cmd.sslapi.GetCertificate(user); + if (cert) + numeric.GetParams()[flag_index].push_back('s'); + + return MOD_RES_PASSTHRU; + } + ModResult OnPreCommand(std::string& command, CommandBase::Params& parameters, LocalUser* user, bool validated) override { if ((command == "OPER") && (validated)) diff --git a/src/modules/m_svshold.cpp b/src/modules/m_svshold.cpp index f226ba780..3da73224f 100644 --- a/src/modules/m_svshold.cpp +++ b/src/modules/m_svshold.cpp @@ -58,8 +58,8 @@ public: { if (!silent) { - ServerInstance->SNO.WriteToSnoMask('x', "Removing expired SVSHOLD %s (set by %s %ld seconds ago): %s", - nickname.c_str(), source.c_str(), (long)(ServerInstance->Time() - set_time), reason.c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "Removing expired SVSHOLD %s (set by %s %s ago): %s", + nickname.c_str(), source.c_str(), InspIRCd::DurationString(ServerInstance->Time() - set_time).c_str(), reason.c_str()); } } @@ -96,7 +96,7 @@ class CommandSvshold : public Command public: CommandSvshold(Module* Creator) : Command(Creator, "SVSHOLD", 1) { - flags_needed = 'o'; this->syntax = "<nickname> [<duration> :<reason>]"; + flags_needed = 'o'; this->syntax = "<nick> [<duration> :<reason>]"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_timedbans.cpp b/src/modules/m_timedbans.cpp index 08158ece8..931c4e707 100644 --- a/src/modules/m_timedbans.cpp +++ b/src/modules/m_timedbans.cpp @@ -118,7 +118,7 @@ class CommandTban : public Command T.chan = channel; TimedBanList.push_back(T); - const std::string addban = user->nick + " added a timed ban on " + mask + " lasting for " + ConvToStr(duration) + " seconds."; + const std::string addban = user->nick + " added a timed ban on " + mask + " lasting for " + InspIRCd::DurationString(duration) + "."; // If halfop is loaded, send notice to halfops and above, otherwise send to ops and above PrefixMode* mh = ServerInstance->Modes.FindPrefixMode('h'); char pfxchar = (mh && mh->name == "halfop") ? mh->GetPrefix() : '@'; diff --git a/src/modules/m_userip.cpp b/src/modules/m_userip.cpp index 444ff6fe7..6e540a206 100644 --- a/src/modules/m_userip.cpp +++ b/src/modules/m_userip.cpp @@ -28,7 +28,7 @@ class CommandUserip : public Command public: CommandUserip(Module* Creator) : Command(Creator,"USERIP", 1) { - syntax = "<nick> [<nick> ...]"; + syntax = "<nick> [<nick>]+"; } CmdResult Handle(User* user, const Params& parameters) override diff --git a/src/modules/m_watch.cpp b/src/modules/m_watch.cpp index 46870eceb..f03f1b5a3 100644 --- a/src/modules/m_watch.cpp +++ b/src/modules/m_watch.cpp @@ -133,7 +133,7 @@ class CommandWatch : public SplitCommand , manager(managerref) { allow_empty_last_param = false; - syntax = "[<C|L|S|l|+<nick1>|-<nick>>]"; + syntax = "C|L|l|S|(+|-)<nick> [(+|-)<nick>]+"; } CmdResult HandleLocal(LocalUser* user, const Params& parameters) override diff --git a/src/modules/m_xline_db.cpp b/src/modules/m_xline_db.cpp index d42423a24..5b3840202 100644 --- a/src/modules/m_xline_db.cpp +++ b/src/modules/m_xline_db.cpp @@ -51,7 +51,8 @@ class ModuleXLineDB : public Module */ void OnAddLine(User* source, XLine* line) override { - dirty = true; + if (!line->from_config) + dirty = true; } /** Called whenever an xline is deleted. @@ -61,7 +62,8 @@ class ModuleXLineDB : public Module */ void OnDelLine(User* source, XLine* line) override { - dirty = true; + if (!line->from_config) + dirty = true; } void OnBackgroundTimer(time_t now) override @@ -113,6 +115,9 @@ class ModuleXLineDB : public Module for (LookupIter i = lookup->begin(); i != lookup->end(); ++i) { XLine* line = i->second; + if (line->from_config) + continue; + stream << "LINE " << line->type << " " << line->Displayable() << " " << line->source << " " << line->set_time << " " << line->duration << " :" << line->reason << std::endl; diff --git a/src/users.cpp b/src/users.cpp index 2010777e0..2cd11121f 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -46,7 +46,7 @@ std::string User::GetModeLetters(bool includeparams) const std::string ret(1, '+'); std::string params; - for (unsigned char i = 'A'; i < 'z'; i++) + for (unsigned char i = 'A'; i <= 'z'; i++) { const ModeHandler* const mh = ServerInstance->Modes.FindMode(i, MODETYPE_USER); if ((!mh) || (!IsModeSet(mh))) diff --git a/src/xline.cpp b/src/xline.cpp index b1cd826bf..0aa16206f 100644 --- a/src/xline.cpp +++ b/src/xline.cpp @@ -265,12 +265,31 @@ bool XLineManager::AddLine(XLine* line, User* user) LookupIter i = x->second.find(line->Displayable()); if (i != x->second.end()) { - // XLine propagation bug was here, if the line to be added already exists and - // it's expired then expire it and add the new one instead of returning false - if ((!i->second->duration) || (ServerInstance->Time() < i->second->expiry)) - return false; + bool silent = false; - ExpireLine(x, i); + // Allow replacing a config line for an updated config line. + if (i->second->from_config && line->from_config) + { + // Nothing changed, skip adding this one. + if (i->second->reason == line->reason) + return false; + + silent = true; + } + // Allow replacing a non-config line for a new config line. + else if (!line->from_config) + { + // X-line propagation bug was here, if the line to be added already exists and + // it's expired then expire it and add the new one instead of returning false + if ((!i->second->duration) || (ServerInstance->Time() < i->second->expiry)) + return false; + } + else + { + silent = true; + } + + ExpireLine(x, i, silent); } } @@ -403,11 +422,13 @@ XLine* XLineManager::MatchesLine(const std::string &type, const std::string &pat } // removes lines that have expired -void XLineManager::ExpireLine(ContainerIter container, LookupIter item) +void XLineManager::ExpireLine(ContainerIter container, LookupIter item, bool silent) { FOREACH_MOD(OnExpireLine, (item->second)); - item->second->DisplayExpiry(); + if (!silent) + item->second->DisplayExpiry(); + item->second->Unset(); /* TODO: Can we skip this loop by having a 'pending' field in the XLine class, which is set when a line @@ -539,7 +560,7 @@ void XLine::DefaultApply(User* u, const std::string &line, bool bancache) if (bancache) { ServerInstance->Logs.Log("BANCACHE", LOG_DEBUG, "BanCache: Adding positive hit (" + line + ") for " + u->GetIPString()); - ServerInstance->BanCache.AddHit(u->GetIPString(), this->type, banReason, this->duration); + ServerInstance->BanCache.AddHit(u->GetIPString(), this->type, banReason, (this->duration > 0 ? (this->expiry - ServerInstance->Time()) : 0)); } } @@ -682,8 +703,8 @@ void ELine::OnAdd() void XLine::DisplayExpiry() { bool onechar = (type.length() == 1); - ServerInstance->SNO.WriteToSnoMask('x', "Removing expired %s%s %s (set by %s %ld seconds ago): %s", - type.c_str(), (onechar ? "-line" : ""), Displayable().c_str(), source.c_str(), (long)(ServerInstance->Time() - set_time), reason.c_str()); + ServerInstance->SNO.WriteToSnoMask('x', "Removing expired %s%s %s (set by %s %s ago): %s", + type.c_str(), (onechar ? "-line" : ""), Displayable().c_str(), source.c_str(), InspIRCd::DurationString(ServerInstance->Time() - set_time).c_str(), reason.c_str()); } const std::string& ELine::Displayable() @@ -750,23 +771,23 @@ XLineFactory* XLineManager::GetFactory(const std::string &type) return n->second; } -void XLineManager::ClearConfigLines() +void XLineManager::ExpireRemovedConfigLines(const std::string& type, const insp::flat_set<std::string>& configlines) { // Nothing to do. if (lookup_lines.empty()) return; - ServerInstance->SNO.WriteToSnoMask('x', "Server rehashing; expiring lines defined in the server config ..."); - for (ContainerIter type = lookup_lines.begin(); type != lookup_lines.end(); ++type) + ContainerIter xlines = lookup_lines.find(type); + if (xlines == lookup_lines.end()) + return; + + for (LookupIter xline = xlines->second.begin(); xline != xlines->second.end(); ) { - for (LookupIter xline = type->second.begin(); xline != type->second.end(); ) - { - // We cache this to avoid iterator invalidation. - LookupIter cachedxline = xline++; - if (cachedxline->second->from_config) - { - ExpireLine(type, cachedxline); - } - } + LookupIter cachedxline = xline++; + if (!cachedxline->second->from_config) + continue; + + if (!configlines.count(cachedxline->second->Displayable())) + ExpireLine(xlines, cachedxline); } } diff --git a/vendor/README.md b/vendor/README.md index c233d6dae..b52166464 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -10,7 +10,7 @@ This directory contains vendored dependencies that are shipped with InspIRCd to **License** — Public Domain -**Website** — [http://openwall.com/crypt/](http://openwall.com/crypt/) +**Website** — [https://www.openwall.com/crypt/](https://www.openwall.com/crypt/) ## http_parser @@ -20,7 +20,7 @@ This directory contains vendored dependencies that are shipped with InspIRCd to **License** — MIT License -**Website** — (https://github.com/nodejs/http-parser)[https://github.com/nodejs/http-parser] +**Website** — [https://github.com/nodejs/http-parser](https://github.com/nodejs/http-parser) ## sha256 diff --git a/win/CMakeLists.txt b/win/CMakeLists.txt index 107102281..be6617b8b 100644 --- a/win/CMakeLists.txt +++ b/win/CMakeLists.txt @@ -104,7 +104,7 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") set(CPACK_NSIS_MUI_ICON "${INSPIRCD_BASE}/win\\\\inspircd.ico") set(CPACK_NSIS_MUI_UNIICON "${INSPIRCD_BASE}/win\\\\inspircd.ico") set(CPACK_NSIS_INSTALLED_ICON_NAME "inspircd.exe") - set(CPACK_NSIS_URL_INFO_ABOUT "http://www.inspircd.org/") + set(CPACK_NSIS_URL_INFO_ABOUT "https://www.inspircd.org") set(CPACK_NSIS_COMPRESSOR "/SOLID zlib") include(CPack) diff --git a/win/NSIS.template.in b/win/NSIS.template.in index 0b74cc98f..2e6abd784 100644 --- a/win/NSIS.template.in +++ b/win/NSIS.template.in @@ -43,7 +43,7 @@ ;--- Component support macros: ---
; The code for the add/remove functionality is from:
-; http://nsis.sourceforge.net/Add/Remove_Functionality
+; https://nsis.sourceforge.io/Add/Remove_Functionality
; It has been modified slightly and extended to provide
; inter-component dependencies.
Var AR_SecFlags
diff --git a/win/README.txt b/win/README.txt index f5b2d8c83..437ff7e4f 100644 --- a/win/README.txt +++ b/win/README.txt @@ -1,9 +1,9 @@ Building InspIRCd for Windows:
Prerequisites:
- Visual Studio 2015 or newer (https://www.visualstudio.com/)
- CMake 2.8 or newer (http://www.cmake.org/)
- If building the installer, NSIS http://nsis.sourceforge.net/
+ Visual Studio 2015 or newer (https://www.visualstudio.com)
+ CMake 2.8 or newer (https://cmake.org)
+ If building the installer, NSIS (https://nsis.sourceforge.io)
Configuring:
First copy any extra modules from extras (such as m_mysql) to the modules directory that you want to build.
@@ -53,4 +53,4 @@ Building the installer: Locate the PACKAGE project on Visual Studio's Solution Explorer and build it. This will generate an InspIRCd-x.x.x.exe
installer in the build directory which is ready to be distributed.
- If you are building using NMake Makefiles or do not want to build the installer in Visual Studio, simply use "cpack".
\ No newline at end of file + If you are building using NMake Makefiles or do not want to build the installer in Visual Studio, simply use "cpack".
|
