1
0
mirror of https://github.com/anope/anope.git synced 2026-06-16 15:34:47 +02:00

Compare commits

...

107 Commits

Author SHA1 Message Date
Sadie Powell 3ae4a022eb Release 2.1.11. 2024-12-01 10:04:21 +00:00
Sadie Powell ea8a692191 Add support for numerics associated with cs_set_misc entries.
This is mainly to allow the URL entry to use RPL_CHANNELURL.
2024-11-29 20:39:22 +00:00
Sadie Powell 026d6c461d Update the change logs. 2024-11-29 17:24:13 +00:00
Sadie Powell 3cbac4bcea Update Send and Recv to use ssize_t instead of int. 2024-11-25 16:14:17 +00:00
Sadie Powell e42b4c21b7 Use the Module * overload of GetModule() in the nickserv module. 2024-11-25 14:43:23 +00:00
Sadie Powell 2464913200 Simplify the duration string logic in Anope::Expires.
This is just duplicating Anope::Duration there's no need to reimplement
a worse version of that here.
2024-11-25 03:02:24 +00:00
Sadie Powell ebea728957 Fix pluralising languages which use the same plural for 0 as 1. 2024-11-25 01:20:03 +00:00
Sadie Powell 233a5bf4cd Add a missing override keyword. 2024-11-25 00:20:25 +00:00
Sadie Powell 7019b27e59 Rework how guest nicks work.
- Use the config setting as a string template instead of as a prefix.
- Allow users of IRCds that have UIDs to use that as the guest nick.
- Fall back to a UID before killing if a guest nick can not be found.
2024-11-25 00:08:30 +00:00
Sadie Powell 70227dc882 Take a constant pointer in GetModule. 2024-11-24 22:36:53 +00:00
Sadie Powell 6178ea644a Fix some minor issues with the Turkish translation. 2024-11-24 01:30:57 +00:00
Sadie Powell df7f0730dd Fix the signon time of services pseudoclients on InspIRCd. 2024-11-23 20:24:08 +00:00
Sadie Powell 331168379f Don't escape messages in the pot file.
This can't be applied to the po files so there's no point doing it.
2024-11-23 15:46:39 +00:00
Val Lorentz 5220963be1 Update the French translation. 2024-11-23 10:59:55 +00:00
Sadie Powell 436dab3eb8 Convert some more strings to plural forms. 2024-11-22 15:32:39 +00:00
Sadie Powell c3055e1cfa Add a plural form overload of SendMessage. 2024-11-22 15:22:23 +00:00
Sadie Powell a27be92e4b Skip removed columns when migrating the database schema. 2024-11-22 14:09:26 +00:00
Sadie Powell faf0ad5f35 Improve language selection.
- Allow selecting languages using an abbreviated language code
  (e.g. en for en_US.UTF-8).
- Preprocess the language list on load as it never changes. This
  allows us to stop special casing the English language.
2024-11-22 13:06:58 +00:00
Sadie Powell e9202916b2 Emplace services when registering them with the core. 2024-11-19 19:55:34 +00:00
Sadie Powell 2cb20ded78 Remove some code that should have been removed in the merge. 2024-11-19 19:55:34 +00:00
Sadie Powell 687bcaa83f Add a plural form overload of CommandSource::Reply. 2024-11-19 17:10:29 +00:00
Sadie Powell 1fb8a624f9 Make an untranslated string translatable. 2024-11-19 17:00:19 +00:00
Sadie Powell b4b51d4828 Merge branch '2.0' into 2.1. 2024-11-19 00:40:24 +00:00
Sadie Powell 7083c424c2 Only process sockets after loading the db when using db_sql{_live}.
This avoids slow startups for the 95% of users who are using the
db_flatfile database backend.
2024-11-19 00:39:00 +00:00
Sadie Powell c55d8450a4 Move the set option to its own module.
This is the first step of rewriting nickname protection.
2024-11-18 12:40:24 +00:00
Sadie Powell 7a20f26b84 Only auto-add timers if they actually have a tick time. 2024-11-18 00:48:50 +00:00
Sadie Powell de16238e01 Process all socket events before connecting to the uplink.
This ensures that the SQL import actually succeeds before we do
something that might terminate the process.
2024-11-16 12:49:45 +00:00
Sadie Powell 240f8b9e50 Halt the column migration if any of the queries fail. 2024-11-16 12:13:17 +00:00
Sadie Powell 656ca80dd0 Migrate old SQL schemas to the current layout. 2024-11-16 03:45:03 +00:00
Sadie Powell d40cbdb8cf Merge branch '2.0' into 2.1. 2024-11-15 15:57:57 +00:00
Sadie Powell a668c8b520 Clarify how to import databases from flatfile to SQL.
Closes #456.
2024-11-15 15:57:41 +00:00
Sadie Powell bc44195a3d Make the account id map also use a checker. 2024-11-15 15:12:50 +00:00
Sadie Powell a7cbe2a139 Add default values to the MySQL tables and use when a column is null. 2024-11-14 13:00:03 +00:00
Sadie Powell 8408bf95c7 Fix an inverted condition. 2024-11-13 12:10:38 +00:00
Sadie Powell 309c342b86 Use the remaining wait time in the registration delay message.
Closes #452.
2024-11-13 11:56:50 +00:00
Sadie Powell 4de59d61d8 Use durations instead of seconds in waiting messages. 2024-11-13 11:56:11 +00:00
Sadie Powell 0dc65cc162 Clean up Anope::Duration and switch to use plural form translation. 2024-11-13 02:57:15 +00:00
Sadie Powell 2e6c90d502 Add support for plural form translation.
Closes #340.
2024-11-13 02:48:13 +00:00
Sadie Powell 127ea3e68a Process all socket events before connecting to the uplink.
This ensures that the SQL import actually succeeds before we do
something that might terminate the process.
2024-11-12 17:24:14 +00:00
Sadie Powell ba11b5eab0 Update the Turkish translation.
Co-authored-by: CaPa CuL <capacul@gmail.com>
2024-11-11 21:59:57 +00:00
Sadie Powell df1c6176b3 Merge branch '2.0' into 2.1. 2024-11-11 17:13:01 +00:00
Sadie Powell 96ccfe4cbe Fix using User::Account where User::IsIdentified should be used.
The former causes a dereference which cause a database update. This
is not good for performance with db_sql_live on bigger networks.
2024-11-11 16:46:56 +00:00
Sadie Powell 8634594cd1 Merge branch '2.0' into 2.1. 2024-11-11 15:45:05 +00:00
Sadie Powell ee160842b3 Fix serialising boolean extension items. 2024-11-11 15:24:40 +00:00
Sadie Powell 613452acba Remove an unnecessary function from db_sql_live. 2024-11-11 10:56:53 +00:00
Sadie Powell 9411dac991 Add a helper function to db_sql(_live) for getting a table name. 2024-11-11 10:44:20 +00:00
TehPeGaSuS aa32f7c926 More updates to the pt_PT translation. 2024-11-08 23:08:41 +00:00
Sadie Powell 517810b208 Make the grammar of the SET privilege description less weird. 2024-11-08 14:25:05 +00:00
Sadie Powell b7f7a91dfb Make the en_US translation file more suitable as a template. 2024-11-08 14:00:15 +00:00
Sadie Powell b6e4c7302e Remove the integer width from chanstats and irc2sql columns.
These are ignored by MySQL so specifying them is meaningless.
2024-11-08 13:21:06 +00:00
Sadie Powell b7590e20c1 Merge branch '2.0' into 2.1. 2024-11-08 13:10:16 +00:00
Sadie Powell 4952a9c852 Migrate from Markdown to YAML issue templates. 2024-11-08 12:07:19 +00:00
Sadie Powell 59647baff9 Avoid unnecessary string copies when calling IsFile. 2024-11-08 00:26:51 +00:00
Sadie Powell 1393518555 Fix some compiler warnings from not checking chdir. 2024-11-07 19:34:46 +00:00
Sadie Powell 51827b94ad Simplify account identifier generation. 2024-11-07 19:33:01 +00:00
Sadie Powell 98c840eb02 Expand the size of some chanstats columns.
Closes #444.
2024-11-07 12:31:47 +00:00
Sadie Powell 24cbb84009 Bump for 2.1.11-git. 2024-11-01 10:00:11 +00:00
Sadie Powell f3c94e5d23 Release 2.1.10. 2024-11-01 09:48:52 +00:00
Sadie Powell f2ab092742 Merge branch '2.0' into 2.1. 2024-10-27 16:14:09 +00:00
Sadie Powell 7d5ca5c90b Switch the city version of geoipupdate to a non-corrupt database.
Closes #439.
2024-10-27 16:13:51 +00:00
Sadie Powell 8ee85efd70 Fix parsing mode changes from users on UnrealIRCd. 2024-10-25 14:50:04 +01:00
Sadie Powell 0cab675825 Fix a typo in the change log. 2024-10-22 16:53:21 +01:00
Sadie Powell f1751dcb21 Replace usestrictprivmsg with something actually useful.
Every IRC server we support (other than Bahamut which is probably
on the chopping bock) uses UIDs so this setting does nothing.

Instead, allow configuring a server-side alias for each service
and use that when servicealias is enabled.
2024-10-22 16:29:22 +01:00
Sadie Powell 8b02613549 Fix some stuff that was missed in commit b94c3740b9. 2024-10-22 14:59:18 +01:00
Sadie Powell c9625ccf3f Update the change logs. 2024-10-22 14:41:52 +01:00
Sadie Powell 435ce51196 Move nickserv/set/message to a new module, kill options:useprivmsg. 2024-10-22 14:27:30 +01:00
TehPeGaSuS 57ac7cb4db Update the cron file name.
name
2024-10-20 23:53:23 +01:00
Sadie Powell 8cb2b801e9 Use the target nick as the default desc for mask access entries. 2024-10-19 17:40:24 +01:00
Sadie Powell 66b45534a8 Deduplicate the access code in cs_statusupdate. 2024-10-19 12:17:33 +01:00
Sadie Powell 499077826c Replace the Facebook ns_set_misc example with a non-URL alternative.
This makes it more clear you can use this for more than just an
URL to an external service.
2024-10-18 18:54:22 +01:00
Sadie Powell bc4d34ebd8 Merge branch '2.0' into 2.1 2024-10-18 11:50:54 +01:00
Sadie Powell f40719787f Fix a change that was missing from the previous commit. 2024-10-18 11:45:19 +01:00
Sadie Powell 934a13c21f Merge branch '2.0' into 2.1. 2024-10-18 11:41:53 +01:00
Sadie Powell e5602f956d Fix marking channels as persistent on InspIRCd and UnrealIRCd. 2024-10-18 11:26:03 +01:00
Sadie Powell de11a19e03 Updated the supported versions in the README. 2024-10-17 16:00:43 +01:00
Sadie Powell b437468b84 Add support for name-only extbans on InspIRCd. 2024-10-16 13:06:47 +01:00
Sadie Powell 0a99571c0f Merge branch '2.0' into 2.1. 2024-10-13 17:17:34 +01:00
Sadie Powell e704fa6266 Update the IRC server to point to Teranova. 2024-10-13 17:15:26 +01:00
Sadie Powell f908514095 Zero errno before calling popen. 2024-10-12 17:54:36 +01:00
Sadie Powell bafcba023c Switch geoipupdate.sh to use a mirror as the original data is gone. 2024-10-12 12:01:00 +01:00
Sadie Powell 9a44b74186 Let the user know about their cert being auto-added to their account. 2024-10-11 18:55:22 +01:00
Sadie Powell 883935c3e0 Merge branch '2.0' into 2.1. 2024-10-11 16:55:36 +01:00
Sadie Powell 6d34054b78 Change the mode lock before removing/adding the PERM mode.
This fixes being unable to unset mlock on the first attempt.
2024-10-11 15:45:02 +01:00
Sadie Powell 3da9b6df0d Fix matching stacked extbans. 2024-10-04 19:04:31 +01:00
Sadie Powell 0ab0e4737c Remove some unnecessary debug logging. 2024-10-04 15:08:44 +01:00
Sadie Powell cdf356ed33 Fix validating named extbans on UnrealIRCd. 2024-10-04 14:57:09 +01:00
Sadie Powell 7d268bb4ca Implement NEXTBANS support on UnrealIRCd.
Closes #431.
2024-10-04 13:25:44 +01:00
Sadie Powell 184350ff4a Fix extracting the mode parameters from MODE on UnrealIRCd. 2024-10-04 13:25:10 +01:00
Sadie Powell 4cdbf560e1 Fix matching extended bans in services.
Extended bans are stored without their prefix. Therefore, we should
not try to strip their prefix before matching.

Closes #288.

Co-authored-by: k4be <k4be@pirc.pl>
2024-10-04 13:01:29 +01:00
Sadie Powell cbccc79d37 Fix parsing extbans on InspIRCd v4. 2024-10-04 11:40:40 +01:00
Sadie Powell 9b188a6c04 Respect EXTBANFORMAT on InspIRCd v4. 2024-10-04 11:20:19 +01:00
Sadie Powell 2f74513246 Change User::SetModesInternal to take a split mode change. 2024-10-02 23:54:36 +01:00
Sadie Powell 94dbb19593 Remove the formatting overload of User::SetModesInternal. 2024-10-02 11:15:42 +01:00
Sadie Powell 8232759a92 Change Channel::SetModesInternal to take a split mode change. 2024-10-02 11:12:24 +01:00
Sadie Powell b006966d25 Bump for 2.1.10-git. 2024-10-01 11:47:23 +01:00
Sadie Powell 6037f63ae5 Release 2.1.9. 2024-10-01 11:46:13 +01:00
Sadie Powell 5cdb65ca52 Update the change log. 2024-10-01 11:42:25 +01:00
Sadie Powell f9e4ca4d06 Raise the default nickname expiry time to one year. 2024-10-01 11:31:50 +01:00
Sadie Powell 66c9be8627 Respect nonicknameownership on InspIRCd v4. 2024-09-26 19:38:44 +01:00
Sadie Powell 546f65c38e Fix some messages not being marked as translatable. 2024-09-26 13:26:02 +01:00
Sadie Powell 9fcb022d5e Allow sending an oper account on InspIRCd. 2024-09-26 12:51:54 +01:00
Sadie Powell 5a0c6b1f18 Fix setting +o on opers on login. 2024-09-26 12:51:54 +01:00
Sadie Powell ade8db023e Bump minimum UnrealIRCd version to 6.0. 2024-09-24 19:56:13 +01:00
Sadie Powell 2ae733bcd1 Merge branch '2.0' into 2.1. 2024-09-17 12:32:33 +01:00
Sadie Powell cc37e6d69a Remove config option for options:warningtimeout.
This hasn't done anything since the early 1.9 releases I'm not sure
why it hasn't been removed already.
2024-09-17 12:27:13 +01:00
Sadie Powell 101c68f786 Fix the Argon2 module not having test vectors. 2024-09-04 23:50:01 +01:00
Sadie Powell ec0cd9e7f9 Bump for 2.1.9-git. 2024-09-01 09:50:24 +01:00
120 changed files with 4346 additions and 5343 deletions
+44
View File
@@ -0,0 +1,44 @@
---
name: Bug report
description: Report a non-security bug in Anope.
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
If you're looking for help with setting up your services please post on [our support forum](https://github.com/orgs/anope/discussions/categories/support) instead.
If you're reporting a crash or other security issue [please read our security policy](https://github.com/anope/anope/security/policy#reporting-a-vulnerability) for how to report security issues privately.
- type: textarea
attributes:
label: Description
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce the issue
validations:
required: true
- type: textarea
attributes:
label: Describe the results you received
validations:
required: true
- type: textarea
attributes:
label: Describe the results you expected
validations:
required: true
- type: input
attributes:
label: Anope version
description: |-
Either the output of `services --version` (2.0) or `anope --version` (2.1).
validations:
required: true
-33
View File
@@ -1,33 +0,0 @@
---
name: Bug report
about: Report a non-security issue with Anope.
---
<!--
Please fill in the template below. It will help us process your bug report a lot faster. If you have multiple bugs to report then please open one issue for each bug.
-->
**Description**
**Steps to reproduce the issue:**
1.
2.
3.
**Describe the results you received:**
**Describe the results you expected:**
**Additional information you deem important (e.g. issue happens only occasionally):**
**Output of `services --version`:**
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
description: Request that a new feature is added to Anope.
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request!
- type: textarea
attributes:
label: Description
validations:
required: true
- type: textarea
attributes:
label: Why this would be useful?
validations:
required: true
-15
View File
@@ -1,15 +0,0 @@
---
name: Feature request
about: Request that a new feature is added to Anope.
---
<!--
Please fill in the template below. It will help us process your feature request a lot faster. If you have multiple features to request then please open one issue for each feature.
-->
**Description**
**Why this would be useful**
+4
View File
@@ -1 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Support forum
url: https://github.com/orgs/anope/discussions/categories/support
about: Please ask support questions here.
+1 -1
View File
@@ -14,6 +14,6 @@ Version | Supported
## Reporting a Vulnerability
Please do not report security vulnerabilities on GitHub. Instead, email the details to team@anope.org or get the attention of a developer in our development IRC channel at irc.anope.org #anope-devel and PM them the details.
Please do not report security vulnerabilities on GitHub. Instead, email the details to team@anope.org or get the attention of a developer in our development IRC channel at irc.teranova.net #anope-devel and PM them the details.
We will triage your issue as soon as possible and try to release a fixed version within a week of receiving your report.
+1
View File
@@ -14,3 +14,4 @@ modules/ssl_openssl.cpp
modules/stats
run/
*.mo
*.pot
+2 -2
View File
@@ -4,7 +4,7 @@ Anope is an open source set of IRC services. It is highly modular, with a vast n
* [Website](https://anope.org)
* [GitHub](https://github.com/anope)
* IRC \#anope on irc.anope.org
* IRC \#anope on irc.teranova.net
## Installation
@@ -33,7 +33,7 @@ Copy conf/anope.example.conf to conf/anope.conf
$ cp conf/anope.example.conf conf/anope.conf
```
Edit anope.conf, configuring the uplink, serverinfo, and protocol module configurations. Example link blocks for popular IRCds are included in the anope.example.conf documentation. The [Anope wiki](https://wiki.anope.org) is also a good source of information. Our support channel is located at #anope on [irc.anope.org](irc://irc.anope.org/#anope).
Edit anope.conf, configuring the uplink, serverinfo, and protocol module configurations. Example link blocks for popular IRCds are included in the the example.conf documentation. The [Anope wiki](https://wiki.anope.org) is also a good source of information. Our support channel is located at #anope on [irc.teranova.net](ircs://irc.teranova.net/anope).
Note that the example configuration file includes other example configuration files. If you want to modify the other example configuration files, copy them (e.g. `modules.example.conf` to `modules.conf`) and modify the `include` directive in `anope.conf` to include the new file.
+1 -1
View File
@@ -1,4 +1,4 @@
# Only install example.chk and anope.example.conf from this directory
# Only install cron.example.sh and anope.example.conf from this directory
# NOTE: I would've had this just find all files in the directory, but that would include files not needed (like this file)
set(DATA cron.example.sh anope.example.conf botserv.example.conf hostserv.example.conf modules.example.conf operserv.example.conf chanserv.example.conf global.example.conf memoserv.example.conf nickserv.example.conf chanstats.example.conf irc2sql.example.conf stats.standalone.example.conf)
install(FILES ${DATA}
+8 -30
View File
@@ -414,12 +414,6 @@ options
*/
readtimeout = 5s
/*
* Sets the interval between sending warning messages for program errors via
* WALLOPS/GLOBOPS.
*/
warningtimeout = 4h
/*
* Sets the (maximum) frequency at which the timeout list is checked. This,
* combined with readtimeout above, determines how accurately timed events,
@@ -436,26 +430,11 @@ options
timeoutcheck = 3s
/*
* If set, this will allow users to let services send PRIVMSGs to them
* instead of NOTICEs. Also see the "msg" option of nickserv:defaults,
* which also toggles the default communication (PRIVMSG or NOTICE) to
* use for unregistered users.
*
* This is a feature that is against the IRC RFC and should be used ONLY
* if absolutely necessary.
*
* This directive is optional, and not recommended.
* If set Anope will tell users to use a server-side alias for messaging
* services instead of /msg. The alias for each service defaults to the
* bot name but can be configured in the service block.
*/
#useprivmsg = yes
/*
* If set, will force services to only respond to PRIVMSGs addresses to
* Nick@ServerName - e.g. NickServ@example.com. This should be used in
* conjunction with IRCd aliases. This directive is optional.
*
* This option will have no effect on some IRCds, such as TS6 IRCds.
*/
#usestrictprivmsg = yes
#servicealias = yes
/*
* If set, Anope will only show /stats o to IRC Operators. This directive
@@ -823,8 +802,6 @@ opertype
*
* This can be used to automatically oper users who identify for services operator accounts, and is
* useful for setting modes such as Plexus's user mode +N.
*
* Note that some IRCds, such as InspIRCd, do not allow directly setting +o, and this will not work.
*/
#modes = "+o"
}
@@ -1172,9 +1149,10 @@ module
/* Whether or not to import data from another database module in to SQL on startup.
* If you enable this, be sure that the database services is configured to use is
* empty and that another database module to import from is loaded before db_sql.
* After you enable this and do a database import you should disable it for
* subsequent restarts.
* empty and that another database module to import from is loaded BEFORE db_sql.
* After you enable this and do a database import you MUST disable it for
* subsequent restarts. If you want to keep writing a flatfile database after the
* SQL import is done you should load db_flatfile AFTER this module.
*
* Note that you can not import databases using db_sql_live. If you want to import
* databases and use db_sql_live you should import them using db_sql, then shut down
+13 -2
View File
@@ -59,6 +59,17 @@ service
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
*/
#channels = "@#services,#mychan"
/*
* The server alias that can be used to securely message this service. If
* your IRC server does not have an alias for this service you can set this
* to an empty string to tell users to use /msg instead.
*
* This setting is ignored when options:servicealias is disabled.
*
* Defaults to the nick of the service if not set.
*/
#alias = "BS"
}
/*
@@ -334,10 +345,10 @@ privilege
/*
* fantasy
*
* Allows 'fantasist' commands to be used in channels.
* Allows fantasy commands (e.g. !kick) to be used in channels.
*
* Provides the commands:
* botserv/set/fantasy - Used for enabling or disabling BotServ's fantasist commands.
* botserv/set/fantasy - Used for enabling or disabling BotServ's fantasy commands.
*/
module
{
+13 -2
View File
@@ -49,6 +49,17 @@ service
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
*/
#channels = "@#services,#mychan"
/*
* The server alias that can be used to securely message this service. If
* your IRC server does not have an alias for this service you can set this
* to an empty string to tell users to use /msg instead.
*
* This setting is ignored when options:servicealias is disabled.
*
* Defaults to the nick of the service if not set.
*/
#alias = "CS"
}
/*
@@ -726,7 +737,7 @@ privilege
privilege
{
name = "SET"
desc = _("Allowed to set channel settings")
desc = _("Allowed to modify channel settings")
rank = 320
level = 9999
flag = "s"
@@ -1245,7 +1256,7 @@ command { service = "ChanServ"; name = "SET NOEXPIRE"; command = "chanserv/saset
* A field named misc_description may be given for use with help output.
*/
module { name = "cs_set_misc" }
command { service = "ChanServ"; name = "SET URL"; command = "chanserv/set/misc"; misc_description = _("Associate a URL with the channel"); }
command { service = "ChanServ"; name = "SET URL"; command = "chanserv/set/misc"; misc_description = _("Associate a URL with the channel"); misc_numeric = 328; }
command { service = "ChanServ"; name = "SET EMAIL"; command = "chanserv/set/misc"; misc_description = _("Associate an email address with the channel"); }
/*
+11
View File
@@ -49,6 +49,17 @@ service
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
*/
#channels = "@#services,#mychan"
/*
* The server alias that can be used to securely message this service. If
* your IRC server does not have an alias for this service you can set this
* to an empty string to tell users to use /msg instead.
*
* This setting is ignored when options:servicealias is disabled.
*
* Defaults to the nick of the service if not set.
*/
#alias = "GL"
}
/*
+11
View File
@@ -49,6 +49,17 @@ service
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
*/
#channels = "@#services,#mychan"
/*
* The server alias that can be used to securely message this service. If
* your IRC server does not have an alias for this service you can set this
* to an empty string to tell users to use /msg instead.
*
* This setting is ignored when options:servicealias is disabled.
*
* Defaults to the nick of the service if not set.
*/
#alias = "HS"
}
/*
+11
View File
@@ -49,6 +49,17 @@ service
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
*/
#channels = "@#services,#mychan"
/*
* The server alias that can be used to securely message this service. If
* your IRC server does not have an alias for this service you can set this
* to an empty string to tell users to use /msg instead.
*
* This setting is ignored when options:servicealias is disabled.
*
* Defaults to the nick of the service if not set.
*/
#alias = "MS"
}
/*
+63 -30
View File
@@ -49,6 +49,17 @@ service
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
*/
#channels = "@#services,#mychan"
/*
* The server alias that can be used to securely message this service. If
* your IRC server does not have an alias for this service you can set this
* to an empty string to tell users to use /msg instead.
*
* This setting is ignored when options:servicealias is disabled.
*
* Defaults to the nick of the service if not set.
*/
#alias = "NS"
}
/*
@@ -106,8 +117,7 @@ module
* - memo_mail: Notify user if they have a new memo by mail
* - autoop: User will be automatically opped in channels they enter and have access to
* - neverop: User can not be added to access lists
* - msg: Messages will be sent as PRIVMSGs instead of NOTICEs, requires options:useprivmsg
* to be enabled as well
* - msg: Messages will be sent as PRIVMSGs instead of NOTICEs
* - ns_keep_modes: Enables keepmodes, which retains user modes across sessions
*
* This directive is optional, if left blank, the options will default to memo_signon, and
@@ -124,9 +134,9 @@ module
/*
* The length of time before a nick's registration expires.
*
* This directive is optional, but recommended. If not set, the default is 90 days.
* This directive is optional, but recommended. If not set, the default is one year.
*/
expire = 90d
expire = 1y
/*
* Prevents the use of the ACCESS and CERT (excluding their LIST subcommand), DROP, FORBID, SUSPEND
@@ -193,13 +203,17 @@ module
releasetimeout = 1m
/*
* When a user's nick is forcibly changed to enforce a "nick kill", their new nick will start
* with this value. The rest will be made up of 6 or 7 digits.
* Make sure this is a valid nick and Nicklen+7 is not longer than the allowed Nicklen on your ircd.
* When a user's nick is forcibly changed to enforce nickname protection their new
* nick will be based on this value. Any # in the value will be replaced with a random
* number. If your IRCd has support for unique identifiers you can also set this to an
* empty string to change a user's nick to their unique identifier.
*
* This directive is optional. If not set it defaults to "Guest"
* Make sure this is a valid nick and that it is is not longer than the maximum nick
* length on your IRCd.
*
* This directive is optional. If not set it defaults to "Guest####"
*/
guestnickprefix = "Guest"
guestnick = "Guest####"
/*
* If set, Anope does not allow ownership of nick names, only ownership of accounts.
@@ -511,23 +525,11 @@ command { service = "NickServ"; name = "RESETPASS"; command = "nickserv/resetpas
* nickserv/set/display, nickserv/saset/display - Used for setting a users display name.
* nickserv/set/email, nickserv/saset/email - Used for setting a users email address.
* nickserv/set/keepmodes, nickserv/saset/keepmodes - Configure whether or not services should retain a user's modes across sessions.
* nickserv/set/kill, nickserv/saset/kill - Used for configuring nickname protection.
* nickserv/set/message, nickserv/saset/message - Used to configure how services send messages to you.
* nickserv/set/neverop, nickserv/saset/neverop - Used to configure whether a user can be added to access lists
* nickserv/saset/noexpire - Used for configuring noexpire, which prevents nicks from expiring.
* nickserv/set/password, nickserv/saset/password - Used for changing a users password.
*/
module
{
name = "ns_set"
/*
* Allow the use of the IMMED option in the NickServ SET KILL command.
*
* This directive is optional.
*/
#allowkillimmed = yes
}
module { name = "ns_set" }
command { service = "NickServ"; name = "SET"; command = "nickserv/set"; }
command { service = "NickServ"; name = "SASET"; command = "nickserv/saset"; permission = "nickserv/saset/"; group = "nickserv/admin"; }
@@ -544,12 +546,6 @@ command { service = "NickServ"; name = "SASET EMAIL"; command = "nickserv/saset/
command { service = "NickServ"; name = "SET KEEPMODES"; command = "nickserv/set/keepmodes"; }
command { service = "NickServ"; name = "SASET KEEPMODES"; command = "nickserv/saset/keepmodes"; permission = "nickserv/saset/keepmodes"; }
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/kill"; }
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/kill"; permission = "nickserv/saset/kill"; }
command { service = "NickServ"; name = "SET MESSAGE"; command = "nickserv/set/message"; }
command { service = "NickServ"; name = "SASET MESSAGE"; command = "nickserv/saset/message"; permission = "nickserv/saset/message"; }
command { service = "NickServ"; name = "SET PASSWORD"; command = "nickserv/set/password"; }
command { service = "NickServ"; name = "SASET PASSWORD"; command = "nickserv/saset/password"; permission = "nickserv/saset/password"; }
@@ -558,6 +554,28 @@ command { service = "NickServ"; name = "SASET NEVEROP"; command = "nickserv/sase
command { service = "NickServ"; name = "SASET NOEXPIRE"; command = "nickserv/saset/noexpire"; permission = "nickserv/saset/noexpire"; }
/*
* ns_set_kill
*
* Provides the commands nickserv/set/kill and kickserv/saset/kill.
*
* Used for configuring nickname protection.
*/
module
{
name = "ns_set_kill"
/*
* Allow the use of the IMMED option in the NickServ SET KILL command.
*
* This directive is optional.
*/
#allowkillimmed = yes
}
command { service = "NickServ"; name = "SET KILL"; command = "nickserv/set/kill"; }
command { service = "NickServ"; name = "SASET KILL"; command = "nickserv/saset/kill"; permission = "nickserv/saset/kill"; }
/*
* ns_set_language
*
@@ -569,6 +587,21 @@ module { name = "ns_set_language" }
command { service = "NickServ"; name = "SET LANGUAGE"; command = "nickserv/set/language"; }
command { service = "NickServ"; name = "SASET LANGUAGE"; command = "nickserv/saset/language"; permission = "nickserv/saset/language"; }
/*
* ns_set_message
*
* Provides the commands nickserv/set/message and nickserv/saset/message.
*
* Allows users to let services send them PRIVMSGs instead of NOTICEs.
*
* This might cause problems with badly written clients as the IRC RFC
* requires that automatic responses to a PRIVMSG use a NOTICE to avoid
* message loops. Only enable this if you are sure this can not happen.
*/
#module { name = "ns_set_message" }
#command { service = "NickServ"; name = "SET MESSAGE"; command = "nickserv/set/message"; }
#command { service = "NickServ"; name = "SASET MESSAGE"; command = "nickserv/saset/message"; permission = "nickserv/saset/message"; }
/*
* ns_set_misc
*
@@ -582,10 +615,10 @@ command { service = "NickServ"; name = "SET URL"; command = "nickserv/set/misc";
command { service = "NickServ"; name = "SASET URL"; command = "nickserv/saset/misc"; misc_description = _("Associate a URL with this account"); permission = "nickserv/saset/url"; group = "nickserv/admin"; }
#command { service = "NickServ"; name = "SET DISCORD"; command = "nickserv/set/misc"; misc_description = _("Associate a Discord account with your account"); }
#command { service = "NickServ"; name = "SASET DISCORD"; command = "nickserv/saset/misc"; misc_description = _("Associate a Discord account with this account"); permission = "nickserv/saset/discord"; group = "nickserv/admin"; }
#command { service = "NickServ"; name = "SET FACEBOOK"; command = "nickserv/set/misc"; misc_description = _("Associate a Facebook URL with your account"); }
#command { service = "NickServ"; name = "SASET FACEBOOK"; command = "nickserv/saset/misc"; misc_description = _("Associate a Facebook URL with this account"); permission = "nickserv/saset/facebook"; group = "nickserv/admin"; }
#command { service = "NickServ"; name = "SET MASTODON"; command = "nickserv/set/misc"; misc_description = _("Associate a Mastodon account with your account"); }
#command { service = "NickServ"; name = "SASET MASTODON"; command = "nickserv/saset/misc"; misc_description = _("Associate a Mastodon account with this account"); permission = "nickserv/saset/mastodon"; group = "nickserv/admin"; }
#command { service = "NickServ"; name = "SET TIMEZONE"; command = "nickserv/set/misc"; misc_description = _("Associate a time zone with your account"); }
#command { service = "NickServ"; name = "SASET TIMEZONE"; command = "nickserv/saset/misc"; misc_description = _("Associate a time zone with this account"); permission = "nickserv/saset/timezone"; group = "nickserv/admin"; }
/*
* ns_suspend
+11
View File
@@ -49,6 +49,17 @@ service
* Prefixes may be given to the channels in the form of mode characters or prefix symbols.
*/
#channels = "@#services,#mychan"
/*
* The server alias that can be used to securely message this service. If
* your IRC server does not have an alias for this service you can set this
* to an empty string to tell users to use /msg instead.
*
* This setting is ignored when options:servicealias is disabled.
*
* Defaults to the nick of the service if not set.
*/
#alias = "OS"
}
/*
-6
View File
@@ -371,12 +371,6 @@ options
*/
readtimeout = 5s
/*
* Sets the interval between sending warning messages for program errors via
* WALLOPS/GLOBOPS.
*/
warningtimeout = 4h
/*
* If set, Anope will only show /stats o to IRC Operators. This directive
* is optional.
+35
View File
@@ -1,3 +1,38 @@
Anope Version 2.1.11
--------------------
Added support for database migrations to the mysql module.
Added support for renicking users to their UID when enforcing nickname protection.
Added support for sending channel URLs to joining users.
Allowed selecting languages using a shorter version of their name.
Changed various messages to use human-readable durations instead of seconds.
Improved the creation of expiry and duration messages.
Improved the translation system with support for plural forms.
Reworked how guest nicknames are generated.
Simplified how account identifiers are allocated.
Anope Version 2.1.10
--------------------
Added support for NEXTBANS on UnrealIRCd.
Changed hostmask access entries added by nick to use that nick as the default description.
Changed modes to be handled internally in their split form.
Changed ns_cert to notify a user that their certificate is being automatically added to their account.
Fixed matching users against extended bans.
Fixed parsing name-only extended bans on InspIRCd.
Fixed respecting the preferred extended ban format on InspIRCd.
Fixed the name of the cron script in the docs.
Updated the list of supported IRCds.
Updated the location of the Anope IRC channels
Anope Version 2.1.9
-------------------
Bumped the minimum supported version of UnrealIRCd to 6.
Fixed granting IRC operator status to services operators.
Fixed making users an IRC operator on InspIRCd.
Fixed nonicknameownership on InspIRCd v4.
Fixed some messages not being translatable.
Fixed the Argon2 module not having test vectors.
Increased the default nickname expiry period to one year.
Anope Version 2.1.8
-------------------
Added account identifiers to the nickserv/info output.
+17
View File
@@ -1,3 +1,20 @@
Anope Version 2.1.11
--------------------
Moved module:allowkilimmed from the ns_set module to the ns_set_kill module.
Moved nickserv/set/kill and nickserv/saset/kill to the ns_set_kill module.
Replaced module:guestnickprefix for the nickserv module with module:guestnick.
Anope Version 2.1.10
--------------------
Added options:servicealias.
Moved nickserv/set/message and nickserv/saset/message to the ns_set_message module.
Removed options:useprivmsg.
Removed options:usestrictprivmsg
Anope Version 2.1.9
-------------------
No significant changes.
Anope Version 2.1.8
-------------------
Added module:preservedisplay to the nickserv module.
+1 -1
View File
@@ -90,4 +90,4 @@ Anope DefCon
6) Support
You might get DefCon support by posting on our online forum, or maybe on
our #anope channel at /server irc.anope.org.
our #anope channel at /server irc.teranova.net.
+5 -5
View File
@@ -60,7 +60,7 @@ Note: You should also read the README and FAQ files!
most likely not work!
If you need help, you should visit https://forum.anope.org/ or #anope on
irc.anope.org. Provide *complete* error output, along with other relevant
irc.teranova.net. Provide *complete* error output, along with other relevant
information eg. OS, compiler and C++ library versions.
See the README file for more information.
@@ -111,17 +111,17 @@ Note: You should also read the README and FAQ files!
A crontab entry will allow you to check periodically whether Anope is
still running, and restart it if not.
First rename the example.chk script that is in Anope path (by default,
this is ~/anope/conf) to anope.chk and edit it. You'll need to
First rename the cron.example.sh script that is in Anope path (by default,
this is ~/anope/conf) to cron.sh and edit it. You'll need to
modify the CONFIGURATION part of the file. Then ensure that the file is
marked as executable by typing chmod +x anope.chk, and try to launch the
marked as executable by typing chmod +x cron.sh, and try to launch the
script to see if it works (Anope must not be running when you do this ;))
When this is done, you'll have to add the crontab entry. Type crontab -e.
This will open the default text editor with the crontab file. Enter the
following (with correct path):
*/5 * * * * /home/ircd/anope/conf/anope.chk >/dev/null 2>&1
*/5 * * * * /home/ircd/anope/conf/cron.sh >/dev/null 2>&1
The */5 at the beginning means "check every 5 minutes". You may replace
the 5 with other another number if you want (but less than 60). Consult
+5 -5
View File
@@ -64,7 +64,7 @@ Note : Vous devrez également lire les fichiers README et FAQ !
recommandée, et Anope ne fonctionnera probablement pas !
Si vous avez besoin d'aide, vous pouvez aller sur le site
https://forum.anope.org/ ou le canal #anope sur irc.anope.org.
https://forum.anope.org/ ou le canal #anope sur irc.teranova.net.
Fournissez *l'essemble* des erreurs qui apparaîssent, en plus de
toutes informations utiles, comme les versions de votre OS, du
compilateur utilisé et de la librairie C++. Lisez le fichier README
@@ -121,11 +121,11 @@ Note : Vous devrez également lire les fichiers README et FAQ !
Une entrée crontab vous permettra de vérifier périodiquement si Anope
est toujours en cours d'exécution et de le redémarrer s'il n'est pas.
D'abord renommez le script example.chk qui est dans les dossiers
d'Anope (par défaut, ~/anope/conf) en anope.chk et modifiez-le.
D'abord renommez le script cron.example.sh qui est dans les dossiers
d'Anope (par défaut, ~/anope/conf) en cron.sh et modifiez-le.
Vous aurez besoin de modifier la partie CONFIGURATION du fichier.
Assurez-vous ensuite que le fichier est marqué comme exécutable en
tapant chmod +x anope.chk et essayez de lancer le script pour voir
tapant chmod +x cron.sh et essayez de lancer le script pour voir
si cela fonctionne (Anope ne doit pas être en marche lorsque vous
testez cela ;))
@@ -133,7 +133,7 @@ Note : Vous devrez également lire les fichiers README et FAQ !
crontab -e. Cela va ouvrir l'éditeur de texte par défaut avec le
fichier crontab. Entrez la ligne suivante (avec le chemin correct) :
*/5 * * * * /home/ircd/anope/conf/anope.chk > /dev/null 2>&1
*/5 * * * * /home/ircd/anope/conf/cron.sh > /dev/null 2>&1
Le */5 au début signifie "vérifier toutes les 5 minutes". Vous pouvez
remplacer le 5 par un autre numéro si vous voulez (mais moins de 60).
+1 -1
View File
@@ -111,7 +111,7 @@ Anope Modules
Use modules at your own risk, and make sure you get them from a
reputable source. You might get module support by contacting the module
author, posting on our online forum, or maybe on our #anope channel
at /server irc.anope.org.
at /server irc.teranova.net.
7) Information for Developers
+4 -4
View File
@@ -167,13 +167,13 @@ Table of Contents
Anope currently works with:
* Bahamut 2.0 or later
* ircd-hybrid 8.2.23 or later
* InspIRCd 3 or later
* ircd-hybrid 8.2.23 or later
* ircd-ratbox 3 or later
* ngIRCd 19.2 or later
* Plexus 3 or later
* Ratbox 2.0.6 or later
* Solanum (all versions)
* UnrealIRCd 4 or later
* UnrealIRCd 6 or later
Anope could also work with some of the daemons derived by the ones listed
above, but there's no support for them if they work or don't work.
@@ -245,7 +245,7 @@ Table of Contents
If you read the documentation carefully, and didn't find the answer to
your question, feel free to post on the website forums or join our irc
channel (irc.anope.org #anope). Once you join our Support channel be as
channel (irc.teranova.net #anope). Once you join our Support channel be as
precise as possible when asking a question, because we have no extraordinary
powers and can't guess things if they aren't provided.
+1 -1
View File
@@ -23,7 +23,7 @@ typedef std::unordered_map<uint64_t, NickCore *> nickcoreid_map;
extern CoreExport Serialize::Checker<nickalias_map> NickAliasList;
extern CoreExport Serialize::Checker<nickcore_map> NickCoreList;
extern CoreExport nickcoreid_map NickCoreIdList;
extern CoreExport Serialize::Checker<nickcoreid_map> NickCoreIdList;
/* A registered nickname.
* It matters that Base is here before Extensible (it is inherited by Serializable)
-7
View File
@@ -473,13 +473,6 @@ namespace Anope
*/
extern CoreExport bool Encrypt(const Anope::string &src, Anope::string &dest);
/** Hashes a buffer with SipHash-2-4
* @param src The start of the buffer to hash
* @param src_sz The total number of bytes in the buffer
* @param key A 16 byte key to hash the buffer with.
*/
extern CoreExport uint64_t SipHash24(const void *src, unsigned long src_sz, const char key[16]);
/** Returns a sequence of data formatted as the format argument specifies.
** After the format parameter, the function expects at least as many
** additional arguments as specified in format.
+5
View File
@@ -31,6 +31,8 @@ public:
time_t lastmsg;
/* Map of actual command names -> service name/permission required */
CommandInfo::map commands;
/* The server-side alias used to message this bot. */
Anope::string alias;
/* Modes the bot should have as configured in service:modes */
Anope::string botmodes;
/* Channels the bot should be in as configured in service:channels */
@@ -126,6 +128,9 @@ public:
*/
CommandInfo *GetCommand(const Anope::string &cname);
/** Get the command that users can use to send a message to this bot. */
Anope::string GetQueryCommand() const;
/** Find a bot by nick
* @param nick The nick
* @param nick_only True to only look by nick, and not by UID
+1 -1
View File
@@ -215,7 +215,7 @@ public:
* @param mode the modes
* @param enforce_mlock true to enforce mlock
*/
void SetModesInternal(MessageSource &source, const Anope::string &mode, time_t ts = 0, bool enforce_mlock = true);
void SetModesInternal(MessageSource &source, const Anope::string &modes, const std::vector<Anope::string> &params, time_t ts = 0, bool enforce_mlock = true);
/** Does the given user match the given list? (CMODE_BAN, CMODE_EXCEPT, etc, a list mode)
* @param u The user
+1
View File
@@ -81,6 +81,7 @@ public:
bool IsFounder(ChannelInfo *ci);
void Reply(const char *message, ...) ATTR_FORMAT(2, 3);
void Reply(int count, const char *singular, const char *plural, ...) ATTR_FORMAT(4, 5);
void Reply(const Anope::string &message);
bool HasCommand(const Anope::string &cmd);
+3 -7
View File
@@ -88,21 +88,17 @@ namespace Configuration
{
/* options:readtimeout */
time_t ReadTimeout;
/* options:useprivmsg */
bool UsePrivmsg;
/* If we should default to privmsging clients */
bool DefPrivmsg;
/* Default language */
Anope::string DefLanguage;
/* options:timeoutcheck */
time_t TimeoutCheck;
/* options:usestrictprivmsg */
bool UseStrictPrivmsg;
/* options:servicealias */
bool ServiceAlias;
/* networkinfo:nickchars */
Anope::string NickChars;
/* either "/msg " or "/" */
Anope::string StrictPrivmsg;
/* List of uplink servers to try and connect to */
std::vector<Uplink> Uplinks;
/* A vector of our logfile options */
@@ -130,7 +126,7 @@ namespace Configuration
void LoadConf(File &file);
void Post(Conf *old);
Block *GetModule(Module *);
Block *GetModule(const Module *);
Block *GetModule(const Anope::string &name);
BotInfo *GetClient(const Anope::string &name);
+1 -1
View File
@@ -194,7 +194,7 @@ public:
void ExtensibleSerialize(const Extensible *e, const Serializable *s, Serialize::Data &data) const override
{
data.Store(this->name, true);
data.Store(this->name, this->HasExt(e));
}
void ExtensibleUnserialize(Extensible *e, Serializable *s, Serialize::Data &data) override
+41 -6
View File
@@ -55,19 +55,54 @@ namespace Language
*/
extern CoreExport const char *Translate(const NickCore *nc, const char *string);
/** Translatesa string to the given language.
/** Translates a string to the given language.
* @param lang The language to translate to
* @param string The string to translate
* @return The translated string if found, else the original string.
*/
extern CoreExport const char *Translate(const char *lang, const char *string);
/** Translates a plural string to the default language.
* @param count The number of items the string is counting.
* @param singular The string to translate if there is one of \p count
* @param plural The string to translate if there is multiple of \p count
* @return The translated string if found, else the original string.
*/
extern CoreExport const char *Translate(int count, const char *singular, const char *plural);
/** Translates a plural string to the language of the given user.
* @param u The user to translate the string for
* @param count The number of items the string is counting.
* @param singular The string to translate if there is one of \p count
* @param plural The string to translate if there is multiple of \p count
* @return The translated string if found, else the original string.
*/
extern CoreExport const char *Translate(User *u, int count, const char *singular, const char *plural);
/** Translates a plural string to the language of the given account.
* @param nc The account to translate the string for
* @param count The number of items the string is counting.
* @param singular The string to translate if there is one of \p count
* @param plural The string to translate if there is multiple of \p count
* @return The translated string if count, else the original string
*/
extern CoreExport const char *Translate(const NickCore *nc, int count, const char *singular, const char *plural);
/** Translates a plural string to the given language.
* @param lang The language to translate to
* @param count The number of items the string is counting.
* @param singular The string to translate if there is one of \p count
* @param plural The string to translate if there is multiple of \p count
* @return The translated string if found, else the original string.
*/
extern CoreExport const char *Translate(const char *lang, int count, const char *singular, const char *plural);
} // namespace Language
/* Commonly used language strings */
#define CONFIRM_DROP _("Please confirm that you want to drop \002%s\002 with \002%s%s DROP %s %s\002")
#define CONFIRM_DROP _("Please confirm that you want to drop \002%s\002 with \002%s DROP %s %s\002")
#define SERVICE_UNAVAILABLE _("Sorry, %s is temporarily unavailable.")
#define MORE_INFO _("\002%s%s HELP %s\002 for more information.")
#define MORE_INFO _("\002%s HELP %s\002 for more information.")
#define BAD_USERHOST_MASK _("Mask must be in the form \037user\037@\037host\037.")
#define BAD_EXPIRY_TIME _("Invalid expiry time.")
#define USERHOST_MASK_TOO_WIDE _("%s coverage is too wide; Please use a more specific mask.")
@@ -93,7 +128,7 @@ namespace Language
#define NO_EXPIRE _("does not expire")
#define LIST_INCORRECT_RANGE _("Incorrect range specified. The correct syntax is \002#\037from\037-\037to\037\002.")
#define NICK_IS_SECURE _("This nickname is registered and protected. If it is your\n" \
"nick, type \002%s%s IDENTIFY \037password\037\002. Otherwise,\n" \
"nick, type \002%s IDENTIFY \037password\037\002. Otherwise,\n" \
"please choose a different nick.")
#define FORCENICKCHANGE_NOW _("This nickname has been registered; you may not use it.")
#define NICK_CANNOT_BE_REGISTERED _("Nickname \002%s\002 may not be registered.")
@@ -111,9 +146,9 @@ namespace Language
#define CHAN_INFO_HEADER _("Information about channel \002%s\002:")
#define CHAN_EXCEPTED _("\002%s\002 matches an except on %s and cannot be banned until the except has been removed.")
#define MEMO_NEW_X_MEMO_ARRIVED _("There is a new memo on channel %s.\n" \
"Type \002%s%s READ %s %zu\002 to read it.")
"Type \002%s READ %s %zu\002 to read it.")
#define MEMO_NEW_MEMO_ARRIVED _("You have a new memo from %s.\n" \
"Type \002%s%s READ %zu\002 to read it.")
"Type \002%s READ %zu\002 to read it.")
#define MEMO_HAVE_NO_MEMOS _("You have no memos.")
#define MEMO_X_HAS_NO_MEMOS _("%s has no memos.")
#define MEMO_HAVE_NO_NEW_MEMOS _("You have no new memos.")
+3 -2
View File
@@ -66,10 +66,11 @@ namespace Message
* @param source The source of the SJOIN
* @param chan The channel the users are joining to
* @param ts The TS for the channel
* @param modes The modes sent with the SJOIN, if any
* @param modes The mode letters sent with the SJOIN, if any
* @param modeparams The mode parameters sent with the SJOIN, if any
* @param users The users and their status, if any
*/
static void SJoin(MessageSource &source, const Anope::string &chan, time_t ts, const Anope::string &modes, const std::list<SJoinUser> &users);
static void SJoin(MessageSource &source, const Anope::string &chan, time_t ts, const Anope::string &modes, const std::vector<Anope::string> &modeparams, const std::list<SJoinUser> &users);
};
struct CoreExport Kick
+4 -1
View File
@@ -216,9 +216,12 @@ template<typename T>
class CoreExport ChannelModeVirtual
: public T
{
Anope::string base;
private:
ChannelMode *basech;
protected:
Anope::string base;
public:
ChannelModeVirtual(const Anope::string &mname, const Anope::string &basename);
+1
View File
@@ -19,4 +19,5 @@ public:
virtual void Validate(User *u) = 0;
virtual void Collide(User *u, NickAlias *na) = 0;
virtual void Release(NickAlias *na) = 0;
virtual bool IsGuestNick(const Anope::string &nick) const = 0;
};
+1 -3
View File
@@ -98,10 +98,8 @@ public:
void Register()
{
std::map<Anope::string, Service *> &smap = Services[this->type];
if (smap.find(this->name) != smap.end())
if (!Services[this->type].emplace(this->name, this).second)
throw ModuleException("Service " + this->type + " with name " + this->name + " already exists");
smap[this->name] = this;
}
void Unregister()
+1
View File
@@ -40,6 +40,7 @@
#define BUFSIZE 1024
#define _(x) x
#define N_(x, y) x, y
#ifndef _WIN32
# define DllExport __attribute__ ((visibility ("default")))
+4 -4
View File
@@ -164,15 +164,15 @@ public:
* @param sz How much to read
* @return Number of bytes received
*/
virtual int Recv(Socket *s, char *buf, size_t sz);
virtual ssize_t Recv(Socket *s, char *buf, size_t sz);
/** Write something to the socket
* @param s The socket
* @param buf The data to write
* @param size The length of the data
*/
virtual int Send(Socket *s, const char *buf, size_t sz);
int Send(Socket *s, const Anope::string &buf);
virtual ssize_t Send(Socket *s, const char *buf, size_t sz);
ssize_t Send(Socket *s, const Anope::string &buf);
/** Accept a connection from a socket
* @param s The socket
@@ -503,7 +503,7 @@ public:
* @param sz The size of the buffer
* @return The amount of data read
*/
int Read(char *data, size_t sz);
ssize_t Read(char *data, size_t sz);
/** Mark the write end of this pipe (non)blocking
* @param state true to enable blocking, false to disable blocking
+6 -5
View File
@@ -107,14 +107,14 @@ protected:
* @param suid The unique identifier of the user.
* @param nc The account the user is identified as, if any
*/
User(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *nc);
User(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const std::vector<Anope::string> &smodeparams, const Anope::string &suid, NickCore *nc);
/** Destroy a user.
*/
virtual ~User();
public:
static User *OnIntroduce(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *nc);
static User *OnIntroduce(const Anope::string &snick, const Anope::string &sident, const Anope::string &shost, const Anope::string &svhost, const Anope::string &sip, Server *sserver, const Anope::string &srealname, time_t ts, const Anope::string &smodes, const Anope::string &suid, NickCore *nc, const std::vector<Anope::string> &smodeparams = {});
/** Update the nickname of a user record accordingly, should be
* called from ircd protocol.
@@ -190,6 +190,7 @@ public:
* @param ... any number of parameters
*/
void SendMessage(BotInfo *source, const char *fmt, ...) ATTR_FORMAT(3, 4);
void SendMessage(BotInfo *source, int count, const char *singular, const char *plural, ...) ATTR_FORMAT(5, 6);
void SendMessage(BotInfo *source, const Anope::string &msg) override;
void SendMessage(CommandSource &source, const Anope::string &msg) override;
@@ -307,10 +308,10 @@ public:
/** Set a string of modes on a user internally
* @param setter who/what is setting the mode
* @param umodes The modes
* @param umodes The mode letters
* @param umodeparams The mode values
*/
void SetModesInternal(const MessageSource &source, const char *umodes, ...) ATTR_FORMAT(3, 4);
void SetModesInternal(const MessageSource &source, const Anope::string &umodes);
void SetModesInternal(const MessageSource &source, const Anope::string &umodes, const std::vector<Anope::string> &umodeparams = {});
/** Get modes set for this user.
* @return A string of modes set on the user
+1567 -3058
View File
File diff suppressed because it is too large Load Diff
+485 -600
View File
File diff suppressed because it is too large Load Diff
+534 -273
View File
File diff suppressed because it is too large Load Diff
+97 -86
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Anope\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-23 18:32+0100\n"
"PO-Revision-Date: 2024-06-23 16:07+0300\n"
"POT-Creation-Date: 2024-11-11 21:27+0000\n"
"PO-Revision-Date: 2024-11-11 22:30+0300\n"
"Last-Translator: CaPaCuL <capacul@gmail.com>\n"
"Language-Team: Turkish\n"
"Language: tr_TR\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.4.4\n"
"X-Generator: Poedit 3.5\n"
#, c-format
msgid "%d channel(s) cleared, and %d channel(s) dropped."
@@ -81,47 +81,47 @@ msgid ""
"It has been created for users that can't host or\n"
"configure a bot, or for use on networks that don't\n"
"allow user bots. Available commands are listed\n"
"below; to use them, type %s%s command. For\n"
"below; to use them, type %s command. For\n"
"more information on a specific command, type\n"
"%s%s %s command.\n"
"%s %s command.\n"
msgstr ""
"%s kendi kanalınızda bir bot bulundurmanıza olanak tanır.\n"
"Bir botu barındıramayan veya yapılandıramayan kullanıcılar için ya da\n"
"kullanıcı botlarına izin vermeyen ağlarda kullanılmak üzere\n"
"oluşturulmuştur. Mevcut komutlar aşağıdaki listelendi;\n"
"bunları kullanmak için %s%s komut yazın.\n"
"Belirli bir komut hakkında daha fazla bilgi için şunu yazın:\n"
"%s%s %s komut.\n"
"bunları kullanmak için %s komut yazın.\n"
"Belirli bir komut hakkında daha fazla bilgi için,\n"
"%s %s komut yazın.\n"
#, c-format
msgid ""
"%s allows you to register a nickname and\n"
"prevent others from using it. The following\n"
"commands allow for registration and maintenance of\n"
"nicknames; to use them, type %s%s command.\n"
"nicknames; to use them, type %s command.\n"
"For more information on a specific command, type\n"
"%s%s %s command.\n"
"%s %s command.\n"
msgstr ""
"%s bir rumuz kaydetmenizi ve başkalarının\n"
"bunu kullanmasının engellenmesini sağlar. Aşağıdaki\n"
"komutlar rumuz kaydı ve düzenlemesşne izin verir;\n"
"bunları kullanmak için %s%s komut yazın.\n"
"bunları kullanmak için %s komut yazın.\n"
"Belirli bir komut hakkında daha fazla bilgi için şunu yazın:\n"
"%s%s %s komut.\n"
"%s %s komut.\n"
#, c-format
msgid ""
"%s allows you to register an account.\n"
"The following commands allow for registration and maintenance of\n"
"accounts; to use them, type %s%s command.\n"
"accounts; to use them, type %s command.\n"
"For more information on a specific command, type\n"
"%s%s %s command.\n"
"%s %s command.\n"
msgstr ""
"%s bir hesap kaydetmenizi sağlar. Aşağıdaki komutlar\n"
"hesap kaydı ve düzenlenmesine yapılmasına izin verir; bunları\n"
"kullanmak için %s%s komut yazın. Belirli bir\n"
"kullanmak için %s komut yazın. Belirli bir\n"
"komut hakkında daha fazla bilgi için şunu yazın:\n"
"%s%s %s komut.\n"
"%s %s komut.\n"
#, c-format
msgid ""
@@ -130,16 +130,16 @@ msgid ""
"malicious users from \"taking over\" channels by limiting\n"
"who is allowed channel operator privileges. Available\n"
"commands are listed below; to use them, type\n"
"%s%s command. For more information on a\n"
"specific command, type %s%s HELP command.\n"
"%s command. For more information on a\n"
"specific command, type %s HELP command.\n"
msgstr ""
"%s kanalların çeşitli yönlerini kaydetmenize ve kontrol\n"
"etmenize olanak tanır. %s, kanal operatörü ayrıcalıklarına izin verilen\n"
"kişileri sınırlayarak, genellikle kötü niyetli kullanıcıların kanalları\n"
"\"ele geçirmesini\" engelleyebilir. Mevcut komutlar aşağıda listelenmiştir;\n"
"bunları kullanmak için %s%s komut yazın.\n"
"bunları kullanmak için %s komut yazın.\n"
"Belirli bir komut hakkında daha fazla bilgi için\n"
"%s%s HELP komut yazın.\n"
"%s HELP komut yazın.\n"
#, c-format
msgid "%s already exists in %s bad words list."
@@ -386,8 +386,8 @@ msgid "%s will now permanently be ignored."
msgstr "%s artık kalıcı olarak yok sayılacak."
#, c-format
msgid "%s%s HELP %s for more information."
msgstr "Daha fazla bilgi için %s%s HELP %s."
msgid "%s HELP %s for more information."
msgstr "Daha fazla bilgi için %s HELP %s."
msgid "ADD nick user host real"
msgstr "ADD rumuz kullanıcı host gerçek_ad"
@@ -457,11 +457,11 @@ msgstr ""
#, c-format
msgid ""
"User access levels can be seen by using the\n"
"%s command; type %s%s HELP LEVELS for\n"
"%s command; type %s HELP LEVELS for\n"
"information."
msgstr ""
"Kullanıcı erişim düzeyleri %s komutu\n"
"kullanılarak görülebilir; bilgi için %s%s HELP LEVELS\n"
"kullanılarak görülebilir; bilgi için %s HELP LEVELS\n"
"yazın."
#, c-format
@@ -865,9 +865,9 @@ msgid ""
"fantasy commands on a channel when prefixed\n"
"with one of the following fantasy characters: %s\n"
" \n"
"Note that users wanting to use fantaisist\n"
"commands MUST have enough access for both\n"
"the FANTASIA and the command they are executing."
"Note that users wanting to use fantasy commands\n"
"MUST have enough access for both the FANTASY\n"
"privilege and the command they are executing."
msgstr ""
" \n"
"Bir kanalda fantezi modunu etkinleştirir veya devre dışı bırakır.\n"
@@ -946,14 +946,14 @@ msgstr ""
#, c-format
msgid ""
" \n"
"See the %s command (%s%s HELP ACCESS) for\n"
"See the %s command (%s HELP ACCESS) for\n"
"information on giving a subset of these privileges to\n"
"other channel users.\n"
msgstr ""
" \n"
"Bu ayrıcalıkların bir alt kümesini diğer kanal kullanıcılarına verme\n"
"hakkında bilgi için %s komutuna\n"
"(%s%s HELP ACCESS) bakın.\n"
"(%s HELP ACCESS) bakın.\n"
msgid ""
" \n"
@@ -1218,12 +1218,12 @@ msgstr ""
#, c-format
msgid ""
" \n"
"Type %s%s HELP command for help on any of the\n"
"Type %s HELP command for help on any of the\n"
"above commands."
msgstr ""
" \n"
"Yukarıdaki komutlardan herhangi biri hakkında yardım almak için\n"
"%s%s HELP komut yazın."
"%s HELP komut yazın."
#, c-format
msgid " %s is online using this oper block."
@@ -1248,10 +1248,6 @@ msgstr " Yüklenme zamanı: %p"
msgid " but %s mysteriously dematerialized."
msgstr " ama nedendir bilinmez %s artık yok."
#, c-format
msgid "\"/msg %s\" is no longer supported. Use \"/msg %s@%s\" or \"/%s\" instead."
msgstr "\"/msg %s\" artık desteklenmiyor. Bunun yerine \"/msg %s@%s\" ve ya \"/%s\" kullanın."
msgid "\"Jupiter\" a server"
msgstr "Bir sunucuyu \"Jupiter\" yapın"
@@ -1811,6 +1807,9 @@ msgstr "Hesap"
msgid "Account %s has already reached the maximum number of simultaneous logins (%u)."
msgstr "%s hesabı zaten maksimum eşzamanlı oturum açma sayısına (%u) ulaştı."
msgid "Account id"
msgstr "Hesap ID"
msgid "Account registered"
msgstr "Hesap kaydedildi"
@@ -2015,15 +2014,15 @@ msgstr "Kanal kurucularıyla sınırlı komutlar verme izni var"
msgid "Allowed to modify channel badwords list"
msgstr "Kanalın küfür listesini değiştirme izni var"
msgid "Allowed to modify channel settings"
msgstr "Kanal ayarlarını yapma izni var"
msgid "Allowed to modify the access list"
msgstr "Erişim listesini değiştirme izni var"
msgid "Allowed to read channel memos"
msgstr "Kanal memolarını okuma izni var"
msgid "Allowed to set channel settings"
msgstr "Kanal ayarlarını yapma izni var"
msgid "Allowed to unban themself"
msgstr "Kendisini unban yapma izni var"
@@ -2953,6 +2952,14 @@ msgstr ""
"erişim listesi boşsa\n"
"kanal düşürülür."
#, c-format
msgid "Changing your usermodes to %s"
msgstr "Kullanıcı modlarınız %s olarak değiştiriliyor"
#, c-format
msgid "Changing your vhost to %s"
msgstr "Vhostunuz %s olarak değiştiriliyor"
msgid "Channel"
msgstr "Kanal"
@@ -3668,7 +3675,7 @@ msgstr "%s için e-posta geçersiz."
msgid "Email matched: %s (%s) to %s."
msgstr "E-posta eşleşti: %s (%s) - %s."
msgid "Enable fantaisist commands"
msgid "Enable fantasy commands"
msgstr "Fantezi komutlarını etkinleştir"
msgid "Enable greet messages"
@@ -3922,7 +3929,7 @@ msgstr ""
"kullanıcıları atacaktır."
msgid "English"
msgstr "İngilizce"
msgstr "Türkçe"
#, c-format
msgid "Entry message %i for %s deleted."
@@ -4193,11 +4200,11 @@ msgid "Info about a loaded module"
msgstr "Yüklü bir modül hakkında bilgi"
#, c-format
msgid "Information for bot %s:"
msgid "Information about bot %s:"
msgstr "%s botu ile ilgili bilgiler:"
#, c-format
msgid "Information for channel %s:"
msgid "Information about channel %s:"
msgstr "%s kanalı ile ilgili bilgiler:"
#, c-format
@@ -4304,7 +4311,7 @@ msgid "LOGONNEWS {ADD|DEL|LIST} [text|num]"
msgstr "LOGONNEWS {ADD|DEL|LIST} [metin|nu.]"
msgid "Language changed to English."
msgstr "Dil İngilizce olarak değiştirildi."
msgstr "Dil Türkçe olarak değiştirildi."
#, c-format
msgid "Language for %s changed to %s."
@@ -4778,7 +4785,7 @@ msgid ""
"Maintains the bad words list for a channel. The bad\n"
"words list determines which words are to be kicked\n"
"when the bad words kicker is enabled. For more information,\n"
"type %s%s HELP KICK %s.\n"
"type %s HELP KICK %s.\n"
" \n"
"The ADD command adds the given word to the\n"
"bad words list. If SINGLE is specified, a kick will be\n"
@@ -4793,7 +4800,7 @@ msgstr ""
"Bir kanal için küfür listesini düzenler.\n"
"küfür listesi, küfürlü konuşanları atma etkinleştirildiğinde\n"
"hangi kelimelerin atılacağını belirler. Daha fazla bilgi\n"
"için %s%s HELP KICK %s yazın.\n"
"için %s HELP KICK %s yazın.\n"
" \n"
"ADD komutu belirtilen kelimeyi küfür\n"
"listesine ekler. SINGLE belirtilirse, yalnızca kullanıcı\n"
@@ -5402,8 +5409,8 @@ msgid "Persistent"
msgstr "Kalıcı"
#, c-format
msgid "Please confirm that you want to drop %s with %s%s DROP %s %s"
msgstr "Lütfen %s rumuzunu droplamak isteğinizi %s%s DROP %s %s ile onaylayın"
msgid "Please confirm that you want to drop %s with %s DROP %s %s"
msgstr "Lütfen %s rumuzunu droplamak isteğinizi %s DROP %s %s ile onaylayın"
msgid "Please contact an Operator to get a vhost assigned to this nick."
msgstr "Bu rumuza atanan bir vHost almak için lütfen bir operle iletişime geçin."
@@ -5899,18 +5906,18 @@ msgstr "OPları koruma %s'de uygulandı."
#, c-format
msgid ""
"See %s%s HELP %s for more information\n"
"See %s HELP %s for more information\n"
"about the access list."
msgstr ""
"Erişim listesi hakkında detaylı bilgi için %s%s HELP %s\n"
"Erişim listesi hakkında detaylı bilgi için %s HELP %s\n"
"komut çıktısına bakın."
#, c-format
msgid ""
"See %s%s HELP %s for more information\n"
"See %s HELP %s for more information\n"
"about the flags system."
msgstr ""
"Bayrak sistemi hakkında detaylı bilgi için %s%s HELP %s\n"
"Bayrak sistemi hakkında detaylı bilgi için %s HELP %s\n"
"komut çıktısına bakın."
msgid "Send a memo to a nick or channel"
@@ -6224,7 +6231,7 @@ msgid ""
"option tells the bot to kick users who say certain words\n"
"on the channels.\n"
"You can define bad words for your channel using the\n"
"BADWORDS command. Type %s%s HELP BADWORDS for\n"
"BADWORDS command. Type %s HELP BADWORDS for\n"
"more information.\n"
" \n"
"ttb is the number of times a user can be kicked\n"
@@ -6236,7 +6243,7 @@ msgstr ""
"söyleyen kullanıcıları atmasını söyler.\n"
"BADWORDS komutunu kullanarak kanalınıza küfür\n"
"tanımlayabilirsiniz. Daha fazla bilgi için\n"
"%s%s HELP BADWORDS yazın.\n"
"%s HELP BADWORDS yazın.\n"
" \n"
"ttb, bir kullanıcının banlanmadan önce atılabileceği\n"
"sayıdır. Ban sistemini aktif hale getirdikten sonra devre dışı\n"
@@ -6461,7 +6468,7 @@ msgid ""
" LIMIT Sets the maximum number of memos you can\n"
" receive\n"
" \n"
"Type %s%s HELP %s option for more information\n"
"Type %s HELP %s option for more information\n"
"on a specific option."
msgstr ""
"Çeşitli memo seçeneklerini ayarlar. seçenek şunlardan biri olabilir:\n"
@@ -6472,7 +6479,7 @@ msgstr ""
" ayarlar\n"
" \n"
"Belirli bir seçenek hakkında daha fazla bilgi için\n"
"%s%s HELP %s seçenek yazın."
"%s HELP %s seçenek yazın."
msgid "Sets various nickname options. option can be one of:"
msgstr "Çeşitli rumuz seçeneklerini ayarlar. seçenek şunlardan biri olabilir:"
@@ -6527,8 +6534,8 @@ msgstr ""
"modların otomatik olarak ayarlanamayacağını unutmayın."
#, c-format
msgid "Setting %s not known. Type %s%s HELP LEVELS for a list of valid settings."
msgstr "%s ayarı bilinmiyor. Geçerli ayarların listesi için %s%s HELP LEVELS yazın."
msgid "Setting %s not known. Type %s HELP LEVELS for a list of valid settings."
msgstr "%s ayarı bilinmiyor. Geçerli ayarların listesi için %s HELP LEVELS yazın."
msgid "Setting for DEBUG must be ON, OFF, or a positive number."
msgstr "DEBUG ayarı ON, OFF veya pozitif bir sayı olmalıdır."
@@ -7438,10 +7445,10 @@ msgstr "%zu memo (%s kanalında) var."
#, c-format
msgid ""
"There is a new memo on channel %s.\n"
"Type %s%s READ %s %zu to read it."
"Type %s READ %s %zu to read it."
msgstr ""
"%s kanalında yeni bir memo var. Okumak için\n"
"%s%s READ %s %zu yazın."
"%s READ %s %zu yazın."
#, c-format
msgid "There is no bot assigned to %s anymore."
@@ -7738,20 +7745,20 @@ msgstr "Bu rumuz askıya alındı."
#, c-format
msgid ""
"This nickname is registered and protected. If it is your\n"
"nick, type %s%s IDENTIFY password. Otherwise,\n"
"nick, type %s IDENTIFY password. Otherwise,\n"
"please choose a different nick."
msgstr ""
"Bu rumuz kayıtlı ve korumalıdır. Eğer sizin\n"
"rumuzunuzsa, %s%s IDENTIFY şifreniz yazın. Aksi halde,\n"
"rumuzunuzsa, %s IDENTIFY şifreniz yazın. Aksi halde,\n"
"kendinize başka bir rumuz seçin."
#, c-format
msgid "To delete, type: %s%s %s %d"
msgstr "Silmek için şunu yazın: %s%s %s %d"
msgid "To delete, type: %s %s %d"
msgstr "Silmek için şunu yazın: %s %s %d"
#, c-format
msgid "To delete, type: %s%s %s %s %d"
msgstr "Silmek için şunu yazın: %s%s %s %s %d"
msgid "To delete, type: %s %s %s %d"
msgstr "Silmek için şunu yazın: %s%s %s %d"
msgid "To protect ops against bot kicks"
msgstr "Opları bot atmalarına karşı korumak için"
@@ -7906,46 +7913,46 @@ msgstr "Türü"
#, c-format
msgid ""
"Type %s%s HELP %s option for more information\n"
"Type %s HELP %s option for more information\n"
"on a specific option."
msgstr ""
"Belirli bir seçenek hakkında daha fazla bilgi için\n"
"%s%s HELP %s seçenek yazın."
"%s HELP %s seçenek yazın."
#, c-format
msgid ""
"Type %s%s HELP %s option for more information\n"
"Type %s HELP %s option for more information\n"
"on a specific option.\n"
" \n"
"Note: access to this command is controlled by the\n"
"level SET."
msgstr ""
"Belirli bir seçenek hakkında daha fazla bilgi için\n"
"%s%s HELP %s seçenek yazın. \n"
"%s HELP %s seçenek yazın. \n"
"Not: Bu komuta erişim SET seviyesi tarafından\n"
"kontrol edilir."
#, c-format
msgid ""
"Type %s%s HELP %s option for more information\n"
"Type %s HELP %s option for more information\n"
"on a specific option. The options will be set on the given\n"
"nickname."
msgstr ""
"Belirli bir seçenek hakkında daha fazla bilgi için\n"
"%s%s HELP %s seçenek yazın. Seçenekler belirtilen\n"
"%s HELP %s seçenek yazın. Seçenekler belirtilen\n"
"rumuz'a göre ayarlanacaktır."
#, c-format
msgid ""
"Type %s%s HELP %s option for more information on a\n"
"Type %s HELP %s option for more information on a\n"
"particular option."
msgstr ""
"Belirli bir seçenek hakkında daha fazla bilgi için\n"
"%s%s HELP %s seçenek yazın."
"Özel bir seçenek hakkında daha fazla bilgi için\n"
"%s HELP %s seçenek yazın."
#, c-format
msgid "Type %s%s SET EMAIL email in order to set your email."
msgstr "E-Postanızı ayarlamak için %s%s SET EMAIL e-posta yazın."
msgid "Type %s SET EMAIL email in order to set your email."
msgstr "E-Postanızı ayarlamak için %s SET EMAIL e-posta yazın."
msgid "Un-Load a module"
msgstr "Bir modülün yüklemesini kaldır"
@@ -7993,16 +8000,16 @@ msgid "Unknown command %s."
msgstr "Bilinmeyen komut %s."
#, c-format
msgid "Unknown command %s. \"%s%s HELP\" for help."
msgstr "Bilinmeyen komut %s. Yardım için: \"%s%s HELP\"."
msgid "Unknown command %s. \"%s HELP\" for help."
msgstr "Bilinmeyen komut %s. Yardım için: \"%s HELP\"."
#, c-format
msgid "Unknown command %s. Did you mean %s?"
msgstr "Bilinmeyen komut %s. %s mi demek istediniz?"
#, c-format
msgid "Unknown command %s. Did you mean %s? \"%s%s HELP\" for help."
msgstr "Bilinmeyen komut %s. %s mi demek istediniz? Yardım için: \"%s%s HELP\"."
msgid "Unknown command %s. Did you mean %s? \"%s HELP\" for help."
msgstr "Bilinmeyen komut %s. %s mi demek istediniz? Yardım için: \"%s HELP\"."
#, c-format
msgid "Unknown mode character %c ignored."
@@ -8347,10 +8354,6 @@ msgstr "Bir kanalı, onun kendi erişim listesine ekleyemezsiniz."
msgid "You can't logout %s, they are a Services Operator."
msgstr "%s oturumunu kapatamazsınız, o bir Servis Operatörü."
#, c-format
msgid "You cannot %s on this network."
msgstr "Bu ağda %s yapamazsınız."
#, c-format
msgid "You cannot set the %c flag."
msgstr "%c bayrağını ayarlayamazsınız."
@@ -8425,10 +8428,10 @@ msgstr "1 yeni memonuz var."
#, c-format
msgid ""
"You have a new memo from %s.\n"
"Type %s%s READ %zu to read it."
"Type %s READ %zu to read it."
msgstr ""
"%s size yeni bir memo gönderdi.\n"
"okumak için %s%s READ %zu yazın."
"okumak için %s READ %zu yazın."
#, c-format
msgid "You have been invited to %s by %s."
@@ -8489,6 +8492,10 @@ msgstr "Diğer Servis Operatörlerinin e-postasını değiştiremezsiniz."
msgid "You may not change the password of other Services Operators."
msgstr "Diğer Servis Operatörlerinin şifresini değiştiremezsiniz."
#, c-format
msgid "You may not drop %s as it is the display nick for the account."
msgstr "Hesabın görüntülenen rumuzu olduğu için %s rumuzunu droplayamazsınız."
msgid "You may not drop other Services Operators' nicknames."
msgstr "Diğer Servis Operatörlerinin rumuzlarını düşüremezsiniz."
@@ -8586,6 +8593,10 @@ msgstr "IRCd'niz SVSPART'ı desteklemiyor."
msgid "Your IRCd does not support vidents. If this is incorrect please report this as a possible bug."
msgstr "IRCd'niz vIdent'i desteklemiyor, eğer bu yanlışsa lütfen bunu olası bir hata olarak bildirin."
#, c-format
msgid "Your SSL certificate fingerprint %s has been automatically added to your certificate list."
msgstr "SSL sertifika parmak iziniz %s otomatik olarak sertifika listenize eklendi."
#, c-format
msgid "Your account %s has been successfully created."
msgstr "Hesabınız %s başarıyla oluşturuldu."
+1 -1
View File
@@ -21,7 +21,6 @@ find ../ \
\) \
-exec \
xgettext \
--escape \
--language=C++ \
--sort-output \
--default-domain=Anope \
@@ -30,6 +29,7 @@ find ../ \
--from-code=utf-8 \
--keyword \
--keyword=_ \
--keyword=N_:1,2 \
{} +
for f in *.po
+4 -4
View File
@@ -153,11 +153,11 @@ public:
"It has been created for users that can't host or\n"
"configure a bot, or for use on networks that don't\n"
"allow user bots. Available commands are listed\n"
"below; to use them, type \002%s%s \037command\037\002. For\n"
"below; to use them, type \002%s \037command\037\002. For\n"
"more information on a specific command, type\n"
"\002%s%s %s \037command\037\002.\n"),
BotServ->nick.c_str(), Config->StrictPrivmsg.c_str(), BotServ->nick.c_str(),
Config->StrictPrivmsg.c_str(), BotServ->nick.c_str(), source.command.c_str());
"\002%s %s \037command\037\002.\n"),
BotServ->nick.c_str(), BotServ->GetQueryCommand().c_str(),
BotServ->GetQueryCommand().c_str(), source.command.c_str());
}
return EVENT_CONTINUE;
+2 -2
View File
@@ -430,7 +430,7 @@ public:
source.Reply(_("Maintains the \002bad words list\002 for a channel. The bad\n"
"words list determines which words are to be kicked\n"
"when the bad words kicker is enabled. For more information,\n"
"type \002%s%s HELP KICK %s\002.\n"
"type \002%s HELP KICK %s\002.\n"
" \n"
"The \002ADD\002 command adds the given word to the\n"
"bad words list. If SINGLE is specified, a kick will be\n"
@@ -440,7 +440,7 @@ public:
"will be done if a user says a word that ends with\n"
"\037word\037. If you don't specify anything, a kick will\n"
"be issued every time \037word\037 is said by a user.\n"
" \n"), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), source.command.c_str());
" \n"), source.service->GetQueryCommand().c_str(), source.command.c_str());
source.Reply(_("The \002DEL\002 command removes the given word from the\n"
"bad words list. If a list of entry numbers is given, those\n"
"entries are deleted. (See the example for LIST below.)\n"
+1 -1
View File
@@ -55,7 +55,7 @@ public:
info[_("Real name")] = bi->realname;
info[_("Created")] = Anope::strftime(bi->created, source.GetAccount());
info[_("Options")] = bi->oper_only ? _("Private") : _("None");
info[_("Used on")] = Anope::ToString(bi->GetChannelCount()) + " channel(s)";
info[_("Used on")] = Anope::printf(Language::Translate(source.nc, N_("%u channel", "%u channels")), bi->GetChannelCount());
FOREACH_MOD(OnBotInfo, (source, bi, ci, info));
+4 -4
View File
@@ -153,11 +153,11 @@ public:
}
}
source.Reply(_("Type \002%s%s HELP %s \037option\037\002 for more information\n"
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information\n"
"on a specific option.\n"
" \n"
"Note: access to this command is controlled by the\n"
"level SET."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), this_name.c_str());
"level SET."), source.service->GetQueryCommand().c_str(), this_name.c_str());
return true;
}
@@ -308,12 +308,12 @@ public:
"option tells the bot to kick users who say certain words\n"
"on the channels.\n"
"You can define bad words for your channel using the\n"
"\002BADWORDS\002 command. Type \002%s%s HELP BADWORDS\002 for\n"
"\002BADWORDS\002 command. Type \002%s HELP BADWORDS\002 for\n"
"more information.\n"
" \n"
"\037ttb\037 is the number of times a user can be kicked\n"
"before it gets banned. Don't give ttb to disable\n"
"the ban system once activated."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str());
"the ban system once activated."), source.service->GetQueryCommand().c_str());
return true;
}
};
+2 -2
View File
@@ -58,8 +58,8 @@ public:
}
}
}
source.Reply(_("Type \002%s%s HELP %s \037option\037\002 for more information on a\n"
"particular option."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), this_name.c_str());
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information on a\n"
"particular option."), source.service->GetQueryCommand().c_str(), this_name.c_str());
return true;
}
+7 -4
View File
@@ -262,9 +262,9 @@ public:
"malicious users from \"taking over\" channels by limiting\n"
"who is allowed channel operator privileges. Available\n"
"commands are listed below; to use them, type\n"
"\002%s%s \037command\037\002. For more information on a\n"
"specific command, type \002%s%s HELP \037command\037\002.\n"),
ChanServ->nick.c_str(), ChanServ->nick.c_str(), Config->StrictPrivmsg.c_str(), ChanServ->nick.c_str(), Config->StrictPrivmsg.c_str(), ChanServ->nick.c_str());
"\002%s \037command\037\002. For more information on a\n"
"specific command, type \002%s HELP \037command\037\002.\n"),
ChanServ->nick.c_str(), ChanServ->nick.c_str(), ChanServ->GetQueryCommand().c_str(), ChanServ->GetQueryCommand().c_str());
return EVENT_CONTINUE;
}
@@ -382,8 +382,11 @@ public:
return EVENT_CONTINUE;
}
void OnPostInit() override
void OnUplinkSync(Server* s) override
{
// We need to do this when the uplink is synced as we may not know if
// the mode exists before then on some IRCds (e.g. InspIRCd).
if (!persist)
return;
+14 -5
View File
@@ -87,6 +87,7 @@ class CommandCSAccess final
void DoAdd(CommandSource &source, ChannelInfo *ci, const std::vector<Anope::string> &params)
{
Anope::string mask = params[2];
Anope::string description = params.size() > 4 ? params[4] : "";
Privilege *p = NULL;
int level = ACCESS_INVALID;
@@ -172,7 +173,11 @@ class CommandCSAccess final
{
User *targ = User::Find(mask, true);
if (targ != NULL)
{
mask = "*!*@" + targ->GetDisplayedHost();
if (description.empty())
description = targ->nick;
}
else
{
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
@@ -216,7 +221,7 @@ class CommandCSAccess final
access->level = level;
access->last_seen = 0;
access->created = Anope::CurTime;
access->description = params.size() > 4 ? params[4] : "";
access->description = description;
ci->AddAccess(access);
FOREACH_MOD(OnAccessAdd, (ci, source, access));
@@ -625,8 +630,8 @@ public:
Anope::string cmd;
if (Command::FindCommandFromService("chanserv/levels", bi, cmd))
source.Reply(_("\002User access levels\002 can be seen by using the\n"
"\002%s\002 command; type \002%s%s HELP LEVELS\002 for\n"
"information."), cmd.c_str(), Config->StrictPrivmsg.c_str(), bi->nick.c_str());
"\002%s\002 command; type \002%s HELP LEVELS\002 for\n"
"information."), cmd.c_str(), bi->GetQueryCommand().c_str());
return true;
}
};
@@ -660,7 +665,10 @@ class CommandCSLevels final
{
Privilege *p = PrivilegeManager::FindPrivilege(what);
if (p == NULL)
source.Reply(_("Setting \002%s\002 not known. Type \002%s%s HELP LEVELS\002 for a list of valid settings."), what.c_str(), Config->StrictPrivmsg.c_str(), source.service->nick.c_str());
{
source.Reply(_("Setting \002%s\002 not known. Type \002%s HELP LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand().c_str());
}
else
{
bool override = !source.AccessFor(ci).HasPriv("FOUNDER");
@@ -701,7 +709,8 @@ class CommandCSLevels final
return;
}
source.Reply(_("Setting \002%s\002 not known. Type \002%s%s HELP LEVELS\002 for a list of valid settings."), what.c_str(), Config->StrictPrivmsg.c_str(), source.service->nick.c_str());
source.Reply(_("Setting \002%s\002 not known. Type \002%s HELP LEVELS\002 for a list of valid settings."),
what.c_str(), source.service->GetQueryCommand().c_str());
}
static void DoList(CommandSource &source, ChannelInfo *ci)
+2 -2
View File
@@ -58,8 +58,8 @@ public:
*code = Anope::Random(15);
}
source.Reply(CONFIRM_DROP, ci->name.c_str(), Config->StrictPrivmsg.c_str(),
source.service->nick.c_str(), ci->name.c_str(), code->c_str());
source.Reply(CONFIRM_DROP, ci->name.c_str(), source.service->GetQueryCommand().c_str(),
ci->name.c_str(), code->c_str());
return;
}
+5 -1
View File
@@ -79,7 +79,7 @@ FlagsAccessProvider *FlagsAccessProvider::ap;
class CommandCSFlags final
: public Command
{
void DoModify(CommandSource &source, ChannelInfo *ci, Anope::string mask, const Anope::string &flags, const Anope::string &description)
void DoModify(CommandSource &source, ChannelInfo *ci, Anope::string mask, const Anope::string &flags, Anope::string description)
{
if (flags.empty())
{
@@ -131,7 +131,11 @@ class CommandCSFlags final
{
User *targ = User::Find(mask, true);
if (targ != NULL)
{
mask = "*!*@" + targ->GetDisplayedHost();
if (description.empty())
description = targ->nick;
}
else
{
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
+2 -2
View File
@@ -100,9 +100,9 @@ public:
Anope::string cmd;
if (Command::FindCommandFromService("chanserv/access", bi, cmd))
source.Reply(_(" \n"
"See the \002%s\002 command (\002%s%s HELP ACCESS\002) for\n"
"See the \002%s\002 command (\002%s HELP ACCESS\002) for\n"
"information on giving a subset of these privileges to\n"
"other channel users.\n"), cmd.c_str(), Config->StrictPrivmsg.c_str(), bi->nick.c_str());
"other channel users.\n"), cmd.c_str(), bi->GetQueryCommand().c_str());
source.Reply(_(" \n"
"NOTICE: In order to register a channel, you must have\n"
"first registered your nickname."));
+8 -6
View File
@@ -59,8 +59,8 @@ public:
c->OnServHelp(source);
}
}
source.Reply(_("Type \002%s%s HELP %s \037option\037\002 for more information on a\n"
"particular option."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), this_name.c_str());
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information on a\n"
"particular option."), source.service->GetQueryCommand().c_str(), this_name.c_str());
return true;
}
};
@@ -513,12 +513,13 @@ public:
/* Set the perm mode */
if (cm)
{
if (ci->c && !ci->c->HasMode("PERM"))
ci->c->SetMode(NULL, cm);
/* Add it to the channels mlock */
ModeLocks *ml = ci->Require<ModeLocks>("modelocks");
if (ml)
ml->SetMLock(cm, true, "", source.GetNick());
if (ci->c && !ci->c->HasMode("PERM"))
ci->c->SetMode(NULL, cm);
}
/* No botserv bot, no channel mode, give them ChanServ.
* Yes, this works fine with no BotServ.
@@ -556,12 +557,13 @@ public:
/* Unset perm mode */
if (cm)
{
if (ci->c && ci->c->HasMode("PERM"))
ci->c->RemoveMode(NULL, cm);
/* Remove from mlock */
ModeLocks *ml = ci->GetExt<ModeLocks>("modelocks");
if (ml)
ml->RemoveMLock(cm, true);
if (ci->c && ci->c->HasMode("PERM"))
ci->c->RemoveMode(NULL, cm);
}
/* No channel mode, no BotServ, but using ChanServ as the botserv bot
* which was assigned when persist was set on
+24
View File
@@ -15,6 +15,7 @@
static Module *me;
static Anope::map<Anope::string> descriptions;
static Anope::map<uint16_t> numerics;
struct CSMiscData;
static Anope::map<ExtensibleItem<CSMiscData> *> items;
@@ -189,6 +190,7 @@ public:
void OnReload(Configuration::Conf *conf) override
{
descriptions.clear();
numerics.clear();
for (int i = 0; i < conf->CountBlock("command"); ++i)
{
@@ -204,9 +206,31 @@ public:
continue;
descriptions[cname] = desc;
auto numeric = block->Get<unsigned>("misc_numeric");
if (numeric >= 1 && numeric <= 999)
numerics["cs_set_misc:" + GetAttribute(cname)] = numeric;
}
}
void OnJoinChannel(User *user, Channel *c) override
{
if (!c->ci || !user->server->IsSynced() || numerics.empty())
return;
for (const auto &[name, ext] : items)
{
auto *data = ext->Get(c->ci);
if (!data)
continue;
auto numeric = numerics.find(name);
if (numeric != numerics.end())
IRCD->SendNumeric(numeric->second, user->GetUID(), c->ci->name, data->data);
}
}
void OnChanInfo(CommandSource &source, ChannelInfo *ci, InfoFormatter &info, bool) override
{
for (const auto &[_, e] : items)
+31 -41
View File
@@ -11,57 +11,47 @@
class StatusUpdate final
: public Module
{
public:
StatusUpdate(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR)
private:
void OnAccessChange(ChannelInfo *ci, ChanAccess *access, bool adding)
{
if (!ci->c)
return;
for (const auto &[_, uc] : ci->c->users)
{
auto *user = uc->user;
ChannelInfo *next;
if (user->server != Me && access->Matches(user, user->Account(), next))
{
auto ag = ci->AccessFor(user);
for (auto *cms : ModeManager::GetStatusChannelModesByRank())
{
if (!ag.HasPriv("AUTO" + cms->name))
ci->c->RemoveMode(NULL, cms, user->GetUID());
}
if (adding)
ci->c->SetCorrectModes(user, true);
}
}
}
public:
StatusUpdate(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
{
}
void OnAccessAdd(ChannelInfo *ci, CommandSource &, ChanAccess *access) override
{
if (ci->c)
{
for (const auto &[_, uc] : ci->c->users)
{
User *user = uc->user;
ChannelInfo *next;
if (user->server != Me && access->Matches(user, user->Account(), next))
{
AccessGroup ag = ci->AccessFor(user);
for (auto *cms : ModeManager::GetStatusChannelModesByRank())
{
if (!ag.HasPriv("AUTO" + cms->name))
ci->c->RemoveMode(NULL, cms, user->GetUID());
}
ci->c->SetCorrectModes(user, true);
}
}
}
OnAccessChange(ci, access, true);
}
void OnAccessDel(ChannelInfo *ci, CommandSource &, ChanAccess *access) override
{
if (ci->c)
{
for (const auto &[_, uc] : ci->c->users)
{
User *user = uc->user;
ChannelInfo *next;
if (user->server != Me && access->Matches(user, user->Account(), next))
{
AccessGroup ag = ci->AccessFor(user);
for (auto *cms : ModeManager::GetStatusChannelModesByRank())
{
if (!ag.HasPriv("AUTO" + cms->name))
ci->c->RemoveMode(NULL, cms, user->GetUID());
}
}
}
}
OnAccessChange(ci, access, false);
}
};
+8 -4
View File
@@ -179,7 +179,11 @@ private:
{
User *targ = User::Find(mask, true);
if (targ != NULL)
{
mask = "*!*@" + targ->GetDisplayedHost();
if (description.empty())
description = targ->nick;
}
else
{
source.Reply(NICK_X_NOT_REGISTERED, mask.c_str());
@@ -590,11 +594,11 @@ public:
source.Reply(_("Alternative methods of modifying channel access lists are\n"
"available."));
if (!access_cmd.empty())
source.Reply(_("See \002%s%s HELP %s\002 for more information\n"
"about the access list."), Config->StrictPrivmsg.c_str(), access_bi->nick.c_str(), access_cmd.c_str());
source.Reply(_("See \002%s HELP %s\002 for more information\n"
"about the access list."), access_bi->GetQueryCommand().c_str(), access_cmd.c_str());
if (!flags_cmd.empty())
source.Reply(_("See \002%s%s HELP %s\002 for more information\n"
"about the flags system."), Config->StrictPrivmsg.c_str(), flags_bi->nick.c_str(), flags_cmd.c_str());
source.Reply(_("See \002%s HELP %s\002 for more information\n"
"about the flags system."), flags_bi->GetQueryCommand().c_str(), flags_cmd.c_str());
}
return true;
}
+44 -44
View File
@@ -212,7 +212,7 @@ class MChanstats final
Anope::string GetDisplay(User *u)
{
if (u && u->Account() && ns_stats.HasExt(u->Account()))
if (u && u->IsIdentified() && ns_stats.HasExt(u->Account()))
return u->Account()->display;
else
return "";
@@ -278,45 +278,45 @@ class MChanstats final
if (!this->HasTable(prefix +"chanstats"))
{
query = "CREATE TABLE `" + prefix + "chanstats` ("
"`id` int(11) NOT NULL AUTO_INCREMENT,"
"`id` int NOT NULL AUTO_INCREMENT,"
"`chan` varchar(64) NOT NULL DEFAULT '',"
"`nick` varchar(64) NOT NULL DEFAULT '',"
"`type` ENUM('total', 'monthly', 'weekly', 'daily') NOT NULL,"
"`letters` int(10) unsigned NOT NULL DEFAULT '0',"
"`words` int(10) unsigned NOT NULL DEFAULT '0',"
"`line` int(10) unsigned NOT NULL DEFAULT '0',"
"`actions` int(10) unsigned NOT NULL DEFAULT '0',"
"`smileys_happy` int(10) unsigned NOT NULL DEFAULT '0',"
"`smileys_sad` int(10) unsigned NOT NULL DEFAULT '0',"
"`smileys_other` int(10) unsigned NOT NULL DEFAULT '0',"
"`kicks` int(10) unsigned NOT NULL DEFAULT '0',"
"`kicked` int(10) unsigned NOT NULL DEFAULT '0',"
"`modes` int(10) unsigned NOT NULL DEFAULT '0',"
"`topics` int(10) unsigned NOT NULL DEFAULT '0',"
"`time0` int(10) unsigned NOT NULL default '0',"
"`time1` int(10) unsigned NOT NULL default '0',"
"`time2` int(10) unsigned NOT NULL default '0',"
"`time3` int(10) unsigned NOT NULL default '0',"
"`time4` int(10) unsigned NOT NULL default '0',"
"`time5` int(10) unsigned NOT NULL default '0',"
"`time6` int(10) unsigned NOT NULL default '0',"
"`time7` int(10) unsigned NOT NULL default '0',"
"`time8` int(10) unsigned NOT NULL default '0',"
"`time9` int(10) unsigned NOT NULL default '0',"
"`time10` int(10) unsigned NOT NULL default '0',"
"`time11` int(10) unsigned NOT NULL default '0',"
"`time12` int(10) unsigned NOT NULL default '0',"
"`time13` int(10) unsigned NOT NULL default '0',"
"`time14` int(10) unsigned NOT NULL default '0',"
"`time15` int(10) unsigned NOT NULL default '0',"
"`time16` int(10) unsigned NOT NULL default '0',"
"`time17` int(10) unsigned NOT NULL default '0',"
"`time18` int(10) unsigned NOT NULL default '0',"
"`time19` int(10) unsigned NOT NULL default '0',"
"`time20` int(10) unsigned NOT NULL default '0',"
"`time21` int(10) unsigned NOT NULL default '0',"
"`time22` int(10) unsigned NOT NULL default '0',"
"`time23` int(10) unsigned NOT NULL default '0',"
"`letters` bigint unsigned NOT NULL DEFAULT '0',"
"`words` bigint unsigned NOT NULL DEFAULT '0',"
"`line` int unsigned NOT NULL DEFAULT '0',"
"`actions` int unsigned NOT NULL DEFAULT '0',"
"`smileys_happy` int unsigned NOT NULL DEFAULT '0',"
"`smileys_sad` int unsigned NOT NULL DEFAULT '0',"
"`smileys_other` int unsigned NOT NULL DEFAULT '0',"
"`kicks` int unsigned NOT NULL DEFAULT '0',"
"`kicked` int unsigned NOT NULL DEFAULT '0',"
"`modes` int unsigned NOT NULL DEFAULT '0',"
"`topics` int unsigned NOT NULL DEFAULT '0',"
"`time0` int unsigned NOT NULL default '0',"
"`time1` int unsigned NOT NULL default '0',"
"`time2` int unsigned NOT NULL default '0',"
"`time3` int unsigned NOT NULL default '0',"
"`time4` int unsigned NOT NULL default '0',"
"`time5` int unsigned NOT NULL default '0',"
"`time6` int unsigned NOT NULL default '0',"
"`time7` int unsigned NOT NULL default '0',"
"`time8` int unsigned NOT NULL default '0',"
"`time9` int unsigned NOT NULL default '0',"
"`time10` int unsigned NOT NULL default '0',"
"`time11` int unsigned NOT NULL default '0',"
"`time12` int unsigned NOT NULL default '0',"
"`time13` int unsigned NOT NULL default '0',"
"`time14` int unsigned NOT NULL default '0',"
"`time15` int unsigned NOT NULL default '0',"
"`time16` int unsigned NOT NULL default '0',"
"`time17` int unsigned NOT NULL default '0',"
"`time18` int unsigned NOT NULL default '0',"
"`time19` int unsigned NOT NULL default '0',"
"`time20` int unsigned NOT NULL default '0',"
"`time21` int unsigned NOT NULL default '0',"
"`time22` int unsigned NOT NULL default '0',"
"`time23` int unsigned NOT NULL default '0',"
"PRIMARY KEY (`id`),"
"UNIQUE KEY `chan` (`chan`,`nick`,`type`),"
"KEY `nick` (`nick`),"
@@ -332,9 +332,9 @@ class MChanstats final
this->RunQuery(query);
}
query = "CREATE PROCEDURE `" + prefix + "chanstats_proc_update`"
"(chan_ VARCHAR(255), nick_ VARCHAR(255), line_ INT(10), letters_ INT(10),"
"words_ INT(10), actions_ INT(10), sm_h_ INT(10), sm_s_ INT(10), sm_o_ INT(10),"
"kicks_ INT(10), kicked_ INT(10), modes_ INT(10), topics_ INT(10))"
"(chan_ VARCHAR(255), nick_ VARCHAR(255), line_ int, letters_ int,"
"words_ int, actions_ int, sm_h_ int, sm_s_ int, sm_o_ int,"
"kicks_ int, kicked_ int, modes_ int, topics_ int)"
"BEGIN "
"DECLARE time_ VARCHAR(20);"
"SET time_ = CONCAT('time', hour(now()));"
@@ -368,7 +368,7 @@ class MChanstats final
query = "CREATE PROCEDURE `" + prefix + "chanstats_proc_chgdisplay`"
"(old_nick varchar(255), new_nick varchar(255))"
"BEGIN "
"DECLARE res_count int(10) unsigned;"
"DECLARE res_count int unsigned;"
"SELECT COUNT(nick) INTO res_count FROM `" + prefix + "chanstats` WHERE nick = new_nick;"
"IF res_count = 0 THEN "
"UPDATE `" + prefix + "chanstats` SET `nick` = new_nick WHERE `nick` = old_nick;"
@@ -381,7 +381,7 @@ class MChanstats final
"smileys_sad_, smileys_other_, kicks_, kicked_, modes_, topics_,"
"time0_, time1_, time2_, time3_, time4_, time5_, time6_, time7_, time8_, time9_,"
"time10_, time11_, time12_, time13_, time14_, time15_, time16_, time17_, time18_,"
"time19_, time20_, time21_, time22_, time23_ INT(10) unsigned;"
"time19_, time20_, time21_, time22_, time23_ int unsigned;"
"DECLARE stats_cursor CURSOR FOR "
"SELECT chan, type, letters, words, line, actions, smileys_happy,"
"smileys_sad, smileys_other, kicks, kicked, modes, topics, time0, time1,"
@@ -532,7 +532,7 @@ public:
void OnTopicUpdated(User *source, Channel *c, const Anope::string &user, const Anope::string &topic) override
{
if (!source || !source->Account() || !c->ci || !cs_stats.HasExt(c->ci))
if (!source || !source->IsIdentified() || !c->ci || !cs_stats.HasExt(c->ci))
return;
query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);";
query.SetValue("channel", c->name);
@@ -555,7 +555,7 @@ public:
private:
void OnModeChange(Channel *c, User *u)
{
if (!u || !u->Account() || !c->ci || !cs_stats.HasExt(c->ci))
if (!u || !u->IsIdentified() || !c->ci || !cs_stats.HasExt(c->ci))
return;
query = "CALL " + prefix + "chanstats_proc_update(@channel@, @nick@, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0);";
+17 -4
View File
@@ -72,6 +72,11 @@ class DBSQL final
bool loaded = false;
bool imported = false;
Anope::string GetTableName(Serialize::Type *s_type)
{
return this->prefix + s_type->GetName();
}
void RunBackground(const Query &q, Interface *iface = NULL)
{
if (!this->sql)
@@ -124,8 +129,8 @@ public:
if (!s_type)
continue;
std::vector<Query> create = this->sql->CreateTable(this->prefix + s_type->GetName(), data);
Query insert = this->sql->BuildInsert(this->prefix + s_type->GetName(), obj->id, data);
auto create = this->sql->CreateTable(GetTableName(s_type), data);
auto insert = this->sql->BuildInsert(GetTableName(s_type), obj->id, data);
if (this->imported)
{
@@ -161,6 +166,14 @@ public:
this->import = block->Get<bool>("import");
}
void OnPostInit() override
{
// If we are importing from flatfile we need to force a socket engine
// flush to ensure it actually gets written to the database before we
// connect to the uplink.
SocketEngine::Process();
}
void OnShutdown() override
{
this->shutting_down = true;
@@ -209,7 +222,7 @@ public:
return;
Serialize::Type *s_type = obj->GetSerializableType();
if (s_type && obj->id > 0)
this->RunBackground("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + Anope::ToString(obj->id));
this->RunBackground("DELETE FROM `" + GetTableName(s_type) + "` WHERE `id` = " + Anope::ToString(obj->id));
this->updated_items.erase(obj);
}
@@ -229,7 +242,7 @@ public:
if (!this->loading_databases && !this->loaded)
return;
Query query("SELECT * FROM `" + this->prefix + sb->GetName() + "`");
Query query("SELECT * FROM `" + GetTableName(sb) + "`");
Result res = this->sql->RunQuery(query);
for (int j = 0; j < res.Rows(); ++j)
+11 -12
View File
@@ -53,13 +53,12 @@ private:
return init && SQL;
}
void RunQuery(const Query &query)
Anope::string GetTableName(Serialize::Type *s_type)
{
/* Can this be threaded? */
this->RunQueryResult(query);
return this->prefix + s_type->GetName();
}
Result RunQueryResult(const Query &query)
Result RunQuery(const Query &query)
{
if (this->CheckSQL())
{
@@ -106,11 +105,11 @@ public:
if (!s_type)
continue;
std::vector<Query> create = this->SQL->CreateTable(this->prefix + s_type->GetName(), data);
auto create = this->SQL->CreateTable(GetTableName(s_type), data);
for (const auto &query : create)
this->RunQueryResult(query);
this->RunQuery(query);
Result res = this->RunQueryResult(this->SQL->BuildInsert(this->prefix + s_type->GetName(), obj->id, data));
auto res = this->RunQuery(this->SQL->BuildInsert(GetTableName(s_type), obj->id, data));
if (res.GetID() && obj->id != res.GetID())
{
/* In this case obj is new, so place it into the object map */
@@ -163,7 +162,7 @@ public:
if (s_type)
{
if (obj->id > 0)
this->RunQuery("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + Anope::ToString(obj->id));
this->RunQuery("DELETE FROM `" + GetTableName(s_type) + "` WHERE `id` = " + Anope::ToString(obj->id));
s_type->objects.erase(obj->id);
}
this->updated_items.erase(obj);
@@ -174,11 +173,11 @@ public:
if (!this->CheckInit() || obj->GetTimestamp() == Anope::CurTime)
return;
Query query("SELECT * FROM `" + this->prefix + obj->GetName() + "` WHERE (`timestamp` >= " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " OR `timestamp` IS NULL)");
Query query("SELECT * FROM `" + GetTableName(obj) + "` WHERE (`timestamp` >= " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " OR `timestamp` IS NULL)");
obj->UpdateTimestamp();
Result res = this->RunQueryResult(query);
Result res = this->RunQuery(query);
bool clear_null = false;
for (int i = 0; i < res.Rows(); ++i)
@@ -236,7 +235,7 @@ public:
else
{
if (!s)
this->RunQuery("UPDATE `" + prefix + obj->GetName() + "` SET `timestamp` = " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " WHERE `id` = " + Anope::ToString(id));
this->RunQuery("UPDATE `" + GetTableName(obj) + "` SET `timestamp` = " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " WHERE `id` = " + Anope::ToString(id));
else
delete s;
}
@@ -245,7 +244,7 @@ public:
if (clear_null)
{
query = "DELETE FROM `" + this->prefix + obj->GetName() + "` WHERE `timestamp` IS NULL";
query = "DELETE FROM `" + GetTableName(obj) + "` WHERE `timestamp` IS NULL";
this->RunQuery(query);
}
}
+1 -1
View File
@@ -67,7 +67,7 @@ public:
if (!blacklist.replies.empty() && !reply)
return;
if (reply && reply->allow_account && user->Account())
if (reply && reply->allow_account && user->IsIdentified())
return;
Anope::string reason = this->blacklist.reason, addr = user->ip.addr();
+12 -1
View File
@@ -139,8 +139,19 @@ public:
, argon2dprovider(this, Argon2_d)
, argon2iprovider(this, Argon2_i)
, argon2idprovider(this, Argon2_id)
{
argon2dprovider.Check({
{ "$argon2d$v=19$m=10,t=10,p=1$VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw$fNS8JrvE8EqKwQ", "" },
{ "$argon2d$v=19$m=10,t=10,p=1$VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw$hTvpprMF0TwszQ", "The quick brown fox jumps over the lazy dog" },
});
argon2iprovider.Check({
{ "$argon2i$v=19$m=10,t=10,p=1$VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw$neE6hYxRp4TCJA", "" },
{ "$argon2i$v=19$m=10,t=10,p=1$VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw$/JAt4FdP1MFD+A", "The quick brown fox jumps over the lazy dog" },
});
argon2idprovider.Check({
{ "$argon2id$v=19$m=10,t=10,p=1$VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw$wuNeHixFDS6Tkg", "" },
{ "$argon2id$v=19$m=10,t=10,p=1$VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw$Po8RcmxZ7vHmdg", "The quick brown fox jumps over the lazy dog" },
});
}
void OnReload(Configuration::Conf *conf) override
+109 -16
View File
@@ -159,28 +159,52 @@ public:
Anope::string FromUnixtime(time_t) override;
Anope::string GetColumnType(Serialize::DataType dt)
const char* GetColumnDefault(Serialize::DataType dt)
{
switch (dt)
{
case Serialize::DataType::BOOL:
return "TINYINT NOT NULL";
case Serialize::DataType::FLOAT:
return "DOUBLE PRECISION NOT NULL";
case Serialize::DataType::INT:
return "BIGINT NOT NULL";
case Serialize::DataType::UINT:
return "0";
case Serialize::DataType::FLOAT:
return "0.0";
case Serialize::DataType::TEXT:
return "NULL";
}
return "NULL"; // Should never be reached
}
bool GetColumnNull(Serialize::DataType dt)
{
return dt == Serialize::DataType::TEXT;
}
const char* GetColumnType(Serialize::DataType dt)
{
switch (dt)
{
case Serialize::DataType::BOOL:
return "TINYINT";
case Serialize::DataType::FLOAT:
return "DOUBLE";
case Serialize::DataType::INT:
return "BIGINT";
case Serialize::DataType::TEXT:
return "TEXT";
case Serialize::DataType::UINT:
return "BIGINT UNSIGNED NOT NULL";
return "BIGINT UNSIGNED";
}
return "TEXT"; // Should never be reached
}
Anope::string GetColumn(Serialize::DataType dt)
{
return Anope::printf("%s %s DEFAULT %s",
GetColumnType(dt),
GetColumnNull(dt) ? "NULL" : "NOT NULL",
GetColumnDefault(dt));
}
};
/** The SQL thread used to execute queries
@@ -424,10 +448,79 @@ std::vector<Query> MySQLService::CreateTable(const Anope::string &table, const D
Result columns = this->RunQuery("SHOW COLUMNS FROM `" + table + "`");
for (int i = 0; i < columns.Rows(); ++i)
{
const Anope::string &column = columns.Get(i, "Field");
const auto column = columns.Get(i, "Field");
Log(LOG_DEBUG) << "mysql: Column #" << i << " for " << table << ": " << column;
if (column == "id" || column == "timestamp")
continue; // These columns are special and aren't part of the data.
known_cols.insert(column);
if (data.data.count(column) == 0)
{
Log(LOG_DEBUG) << "mysql: Column has been removed from the data set: " << column;
continue;
}
// We know the column exists but is the type correct?
auto update = false;
const auto stype = data.GetType(column);
auto coldef = columns.Get(i, "Default");
if (coldef.empty())
coldef = "NULL";
const auto *newcoldef = GetColumnDefault(stype);
if (!coldef.equals_ci(newcoldef))
{
Log(LOG_DEBUG) << "mysql: Updating the default of " << column << " from " << coldef << " to " << newcoldef;
update = true;
}
const auto colnull = columns.Get(i, "Null");
const auto newcolnull = GetColumnNull(stype) ? "YES" : "NO";
if (!colnull.equals_ci(newcolnull))
{
Log(LOG_DEBUG) << "mysql: Updating the nullability of " << column << " from " << colnull << " to " << newcolnull;
update = true;
}
const auto coltype = columns.Get(i, "Type");
const auto *newcoltype = GetColumnType(stype);
if (!coltype.equals_ci(newcoltype))
{
Log(LOG_DEBUG) << "mysql: Updating the type of " << column << " from " << coltype << " to " << newcoltype;
update = true;
}
if (update)
{
// We can't just use MODIFY COLUMN here because the value may not
// be valid and we may need to replace with the default.
auto res = this->RunQuery(Anope::printf("ALTER TABLE `%s` ADD COLUMN `%s_new` %s; ",
table.c_str(), column.c_str(), GetColumn(stype).c_str()));
if (res)
{
res = this->RunQuery(Anope::printf("UPDATE IGNORE `%s` SET `%s_new` = %s; ",
table.c_str(), column.c_str(), column.c_str()));
}
if (res)
{
res = this->RunQuery(Anope::printf("ALTER TABLE `%s` DROP COLUMN `%s`; ",
table.c_str(), column.c_str()));
}
if (res)
{
res = this->RunQuery(Anope::printf("ALTER TABLE `%s` RENAME COLUMN `%s_new` TO `%s`; ",
table.c_str(), column.c_str(), column.c_str()));
}
if (!res)
Log(LOG_DEBUG) << "Failed to migrate the " << column << " column: " << res.GetError();
}
}
}
@@ -439,7 +532,7 @@ std::vector<Query> MySQLService::CreateTable(const Anope::string &table, const D
{
known_cols.insert(column);
query_text += ", `" + column + "` " + GetColumnType(data.GetType(column));
query_text += ", `" + column + "` " + GetColumn(data.GetType(column));
}
query_text += ", PRIMARY KEY (`id`), KEY `timestamp_idx` (`timestamp`)) ROW_FORMAT=DYNAMIC";
queries.push_back(query_text);
@@ -453,7 +546,7 @@ std::vector<Query> MySQLService::CreateTable(const Anope::string &table, const D
known_cols.insert(column);
Anope::string query_text = "ALTER TABLE `" + table + "` ADD `" + column + "` " + GetColumnType(data.GetType(column));
Anope::string query_text = "ALTER TABLE `" + table + "` ADD `" + column + "` " + GetColumn(data.GetType(column));
queries.push_back(query_text);
}
@@ -467,7 +560,7 @@ Query MySQLService::BuildInsert(const Anope::string &table, unsigned int id, Dat
/* Empty columns not present in the data set */
for (const auto &known_col : this->active_schema[table])
{
if (known_col != "id" && known_col != "timestamp" && data.data.count(known_col) == 0)
if (data.data.count(known_col) == 0)
data[known_col] << "";
}
@@ -498,7 +591,7 @@ Query MySQLService::BuildInsert(const Anope::string &table, unsigned int id, Dat
case Serialize::DataType::UINT:
{
if (buf.empty())
buf = "0";
buf = "DEFAULT";
escape = false;
break;
}
@@ -507,7 +600,7 @@ Query MySQLService::BuildInsert(const Anope::string &table, unsigned int id, Dat
{
if (buf.empty())
{
buf = "NULL";
buf = "DEFAULT";
escape = false;
}
break;
+8 -8
View File
@@ -51,14 +51,14 @@ public:
* @param sz How much to read
* @return Number of bytes received
*/
int Recv(Socket *s, char *buf, size_t sz) override;
ssize_t Recv(Socket *s, char *buf, size_t sz) override;
/** Write something to the socket
* @param s The socket
* @param buf The data to write
* @param size The length of the data
*/
int Send(Socket *s, const char *buf, size_t sz) override;
ssize_t Send(Socket *s, const char *buf, size_t sz) override;
/** Accept a connection from a socket
* @param s The socket
@@ -318,7 +318,7 @@ public:
static void CheckFile(const Anope::string &filename)
{
if (!Anope::IsFile(filename.c_str()))
if (!Anope::IsFile(filename))
{
Log() << "File does not exist: " << filename;
throw ConfigException("Error loading certificate/private key");
@@ -339,7 +339,7 @@ public:
GnuTLS::X509CertCredentials *newcred = new GnuTLS::X509CertCredentials(certfile, keyfile);
// DH params is not mandatory
if (Anope::IsFile(dhfile.c_str()))
if (Anope::IsFile(dhfile))
{
try
{
@@ -384,9 +384,9 @@ void MySSLService::Init(Socket *s)
s->io = new SSLSocketIO();
}
int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
ssize_t SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
{
int ret = gnutls_record_recv(this->sess, buf, sz);
ssize_t ret = gnutls_record_recv(this->sess, buf, sz);
if (ret > 0)
TotalRead += ret;
@@ -411,9 +411,9 @@ int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
return ret;
}
int SSLSocketIO::Send(Socket *s, const char *buf, size_t sz)
ssize_t SSLSocketIO::Send(Socket *s, const char *buf, size_t sz)
{
int ret = gnutls_record_send(this->sess, buf, sz);
ssize_t ret = gnutls_record_send(this->sess, buf, sz);
if (ret > 0)
TotalWritten += ret;
+7 -7
View File
@@ -52,14 +52,14 @@ public:
* @param sz How much to read
* @return Number of bytes received
*/
int Recv(Socket *s, char *buf, size_t sz) override;
ssize_t Recv(Socket *s, char *buf, size_t sz) override;
/** Write something to the socket
* @param s The socket
* @param buf The data to write
* @param size The length of the data
*/
int Send(Socket *s, const char *buf, size_t sz) override;
ssize_t Send(Socket *s, const char *buf, size_t sz) override;
/** Accept a connection from a socket
* @param s The socket
@@ -149,7 +149,7 @@ public:
this->certfile = Anope::ExpandConfig(config->Get<const Anope::string>("cert", "fullchain.pem"));
this->keyfile = Anope::ExpandConfig(config->Get<const Anope::string>("key", "privkey.pem"));
if (Anope::IsFile(this->certfile.c_str()))
if (Anope::IsFile(this->certfile))
{
if (!SSL_CTX_use_certificate_chain_file(client_ctx, this->certfile.c_str()) || !SSL_CTX_use_certificate_chain_file(server_ctx, this->certfile.c_str()))
throw ConfigException("Error loading certificate");
@@ -159,7 +159,7 @@ public:
else
Log() << "Unable to open certificate " << this->certfile;
if (Anope::IsFile(this->keyfile.c_str()))
if (Anope::IsFile(this->keyfile))
{
if (!SSL_CTX_use_PrivateKey_file(client_ctx, this->keyfile.c_str(), SSL_FILETYPE_PEM) || !SSL_CTX_use_PrivateKey_file(server_ctx, this->keyfile.c_str(), SSL_FILETYPE_PEM))
throw ConfigException("Error loading private key");
@@ -168,7 +168,7 @@ public:
}
else
{
if (Anope::IsFile(this->certfile.c_str()))
if (Anope::IsFile(this->certfile))
throw ConfigException("Error loading private key " + this->keyfile + " - file not found");
else
Log() << "Unable to open private key " << this->keyfile;
@@ -237,7 +237,7 @@ SSLSocketIO::SSLSocketIO()
this->sslsock = NULL;
}
int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
ssize_t SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
{
int i = SSL_read(this->sslsock, buf, sz);
if (i > 0)
@@ -256,7 +256,7 @@ int SSLSocketIO::Recv(Socket *s, char *buf, size_t sz)
return i;
}
int SSLSocketIO::Send(Socket *s, const char *buf, size_t sz)
ssize_t SSLSocketIO::Send(Socket *s, const char *buf, size_t sz)
{
int i = SSL_write(this->sslsock, buf, sz);
if (i > 0)
+1 -1
View File
@@ -169,7 +169,7 @@ public:
}
// Command requires registered users only
if (!cmd->AllowUnregistered() && !u->Account())
if (!cmd->AllowUnregistered() && !u->IsIdentified())
return;
if (params.size() < cmd->min_params)
+1 -1
View File
@@ -192,7 +192,7 @@ public:
* to has synced, or we'll get greet-floods when the net
* recovers from a netsplit. -GD
*/
if (!c->ci || !c->ci->bi || !user->server->IsSynced() || !user->Account())
if (!c->ci || !c->ci->bi || !user->server->IsSynced() || !user->IsIdentified())
return;
Anope::string *greet = ns_greet.Get(user->Account());
+2 -1
View File
@@ -157,7 +157,8 @@ public:
time_t send_delay = Config->GetModule("memoserv")->Get<time_t>("senddelay");
if (Config->GetModule(this->owner)->Get<bool>("memooper") && send_delay > 0 && u && u->lastmemosend + send_delay > Anope::CurTime)
{
source.Reply(_("Please wait %lu seconds before requesting a new vhost."), (unsigned long)send_delay);
auto waitperiod = (u->lastmemosend + send_delay) - Anope::CurTime;
source.Reply(_("Please wait %s before requesting a new vhost."), Anope::Duration(waitperiod, source.GetAccount()).c_str());
u->lastmemosend = Anope::CurTime;
return;
}
+2 -2
View File
@@ -107,7 +107,7 @@ void IRC2SQL::OnUserConnect(User *u, bool &exempt)
query.SetValue("ident", u->GetIdent());
query.SetValue("vident", u->GetVIdent());
query.SetValue("secure", u->IsSecurelyConnected() ? "Y" : "N");
query.SetValue("account", u->Account() ? u->Account()->display : "");
query.SetValue("account", u->IsIdentified() ? u->Account()->display : "");
query.SetValue("fingerprint", u->fingerprint);
query.SetValue("signon", u->signon);
query.SetValue("server", u->server->GetName());
@@ -175,7 +175,7 @@ void IRC2SQL::OnUserLogin(User *u)
{
query = "UPDATE `" + prefix + "user` SET account=@account@ WHERE nick=@nick@";
query.SetValue("nick", u->nick);
query.SetValue("account", u->Account() ? u->Account()->display : "");
query.SetValue("account", u->IsIdentified() ? u->Account()->display : "");
this->RunQuery(query);
}
+14 -14
View File
@@ -80,14 +80,14 @@ void IRC2SQL::CheckTables()
if (!this->HasTable(prefix + "server"))
{
query = "CREATE TABLE `" + prefix + "server` ("
"`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,"
"`id` int UNSIGNED NOT NULL AUTO_INCREMENT,"
"`name` varchar(64) NOT NULL,"
"`hops` tinyint(3) NOT NULL,"
"`hops` tinyint NOT NULL,"
"`comment` varchar(255) NOT NULL,"
"`link_time` datetime DEFAULT NULL,"
"`split_time` datetime DEFAULT NULL,"
"`version` varchar(127) DEFAULT NULL,"
"`currentusers` int(15) DEFAULT 0,"
"`currentusers` int DEFAULT 0,"
"`online` enum('Y','N') NOT NULL DEFAULT 'Y',"
"`ulined` enum('Y','N') NOT NULL DEFAULT 'N',"
"PRIMARY KEY (`id`),"
@@ -98,7 +98,7 @@ void IRC2SQL::CheckTables()
if (!this->HasTable(prefix + "chan"))
{
query = "CREATE TABLE `" + prefix + "chan` ("
"`chanid` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,"
"`chanid` int UNSIGNED NOT NULL AUTO_INCREMENT,"
"`channel` varchar(255) NOT NULL,"
"`topic` varchar(512) DEFAULT NULL,"
"`topicauthor` varchar(255) DEFAULT NULL,"
@@ -112,7 +112,7 @@ void IRC2SQL::CheckTables()
if (!this->HasTable(prefix + "user"))
{
query = "CREATE TABLE `" + prefix + "user` ("
"`nickid` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,"
"`nickid` int UNSIGNED NOT NULL AUTO_INCREMENT,"
"`nick` varchar(255) NOT NULL DEFAULT '',"
"`host` varchar(255) NOT NULL DEFAULT '',"
"`vhost` varchar(255) NOT NULL DEFAULT '',"
@@ -127,7 +127,7 @@ void IRC2SQL::CheckTables()
"`fingerprint` varchar(128) NOT NULL DEFAULT '',"
"`signon` datetime DEFAULT NULL,"
"`server` varchar(255) NOT NULL DEFAULT '',"
"`servid` int(11) UNSIGNED NOT NULL DEFAULT '0',"
"`servid` int UNSIGNED NOT NULL DEFAULT '0',"
"`uuid` varchar(32) NOT NULL DEFAULT '',"
"`oper` enum('Y','N') NOT NULL DEFAULT 'N',"
"`away` enum('Y','N') NOT NULL DEFAULT 'N',"
@@ -147,8 +147,8 @@ void IRC2SQL::CheckTables()
if (!this->HasTable(prefix + "ison"))
{
query = "CREATE TABLE `" + prefix + "ison` ("
"`nickid` int(11) unsigned NOT NULL default '0',"
"`chanid` int(11) unsigned NOT NULL default '0',"
"`nickid` int unsigned NOT NULL default '0',"
"`chanid` int unsigned NOT NULL default '0',"
"`modes` varchar(255) NOT NULL default '',"
"PRIMARY KEY (`nickid`,`chanid`),"
"KEY `modes` (`modes`)"
@@ -159,7 +159,7 @@ void IRC2SQL::CheckTables()
{
query = "CREATE TABLE `" + prefix + "maxusers` ("
"`name` VARCHAR(255) NOT NULL,"
"`maxusers` INT(15) NOT NULL,"
"`maxusers` int NOT NULL,"
"`maxtime` DATETIME NOT NULL,"
"`lastused` DATETIME NOT NULL,"
"UNIQUE KEY `name` (`name`)"
@@ -200,12 +200,12 @@ void IRC2SQL::CheckTables()
"(nick_ varchar(255), host_ varchar(255), vhost_ varchar(255), "
"chost_ varchar(255), realname_ varchar(255), ip_ varchar(255), "
"ident_ varchar(255), vident_ varchar(255), account_ varchar(255), "
"secure_ enum('Y','N'), fingerprint_ varchar(255), signon_ int(15), "
"secure_ enum('Y','N'), fingerprint_ varchar(255), signon_ int, "
"server_ varchar(255), uuid_ varchar(32), modes_ varchar(255), "
"oper_ enum('Y','N')) "
"BEGIN "
"DECLARE cur int(15);"
"DECLARE max int(15);"
"DECLARE cur int;"
"DECLARE max int;"
"INSERT INTO `" + prefix + "user` "
"(nick, host, vhost, chost, realname, ip, ident, vident, account, "
"secure, fingerprint, signon, server, uuid, modes, oper) "
@@ -304,8 +304,8 @@ void IRC2SQL::CheckTables()
query = "CREATE PROCEDURE `"+ prefix + "JoinUser`"
"(nick_ varchar(255), channel_ varchar(255), modes_ varchar(255)) "
"BEGIN "
"DECLARE cur int(15);"
"DECLARE max int(15);"
"DECLARE cur int;"
"DECLARE max int;"
"INSERT INTO `" + prefix + "ison` (nickid, chanid, modes) "
"SELECT u.nickid, c.chanid, modes_ "
"FROM " + prefix + "user AS u, " + prefix + "chan AS c "
+1 -1
View File
@@ -145,7 +145,7 @@ public:
{
User *u = User::Find(uid);
if (!u || !u->Account() || r.empty())
if (!u || !u->IsIdentified() || r.empty())
return;
try
+1 -1
View File
@@ -24,7 +24,7 @@ public:
void OnResult(const LDAPResult &r) override
{
if (!u || !u->Account())
if (!u || !u->IsIdentified())
return;
NickCore *nc = u->Account();
+6 -6
View File
@@ -100,8 +100,8 @@ public:
{
if (ci->AccessFor(cu->user).HasPriv("MEMO"))
{
if (cu->user->Account() && cu->user->Account()->HasExt("MEMO_RECEIVE"))
cu->user->SendMessage(MemoServ, MEMO_NEW_X_MEMO_ARRIVED, ci->name.c_str(), Config->StrictPrivmsg.c_str(), MemoServ->nick.c_str(), ci->name.c_str(), mi->memos->size());
if (cu->user->IsIdentified() && cu->user->Account()->HasExt("MEMO_RECEIVE"))
cu->user->SendMessage(MemoServ, MEMO_NEW_X_MEMO_ARRIVED, ci->name.c_str(), MemoServ->GetQueryCommand().c_str(), ci->name.c_str(), mi->memos->size());
}
}
}
@@ -116,7 +116,7 @@ public:
{
User *user = User::Find(na->nick, true);
if (user && user->IsIdentified())
user->SendMessage(MemoServ, MEMO_NEW_MEMO_ARRIVED, source.c_str(), Config->StrictPrivmsg.c_str(), MemoServ->nick.c_str(), mi->memos->size());
user->SendMessage(MemoServ, MEMO_NEW_MEMO_ARRIVED, source.c_str(), MemoServ->GetQueryCommand().c_str(), mi->memos->size());
}
}
@@ -139,7 +139,7 @@ public:
if (nc->memos.GetMemo(i)->unread)
++newcnt;
if (newcnt > 0)
u->SendMessage(MemoServ, newcnt == 1 ? _("You have 1 new memo.") : _("You have %d new memos."), newcnt);
u->SendMessage(MemoServ, newcnt, N_("You have %d new memo.", "You have %d new memos."), newcnt);
if (nc->memos.memomax > 0 && nc->memos.memos->size() >= static_cast<unsigned>(nc->memos.memomax))
{
if (nc->memos.memos->size() > static_cast<unsigned>(nc->memos.memomax))
@@ -229,8 +229,8 @@ public:
if (!params.empty() || source.c || source.service != *MemoServ)
return;
source.Reply(_(" \n"
"Type \002%s%s HELP \037command\037\002 for help on any of the\n"
"above commands."), Config->StrictPrivmsg.c_str(), MemoServ->nick.c_str());
"Type \002%s HELP \037command\037\002 for help on any of the\n"
"above commands."), MemoServ->GetQueryCommand().c_str());
}
};
+2 -2
View File
@@ -91,9 +91,9 @@ public:
if (Command::FindCommandFromService("memoserv/del", bi, cmd))
{
if (ci)
source.Reply(_("To delete, type: \002%s%s %s %s %d\002"), Config->StrictPrivmsg.c_str(), bi->nick.c_str(), cmd.c_str(), ci->name.c_str(), index + 1);
source.Reply(_("To delete, type: \002%s %s %s %d\002"), bi->GetQueryCommand().c_str(), cmd.c_str(), ci->name.c_str(), index + 1);
else
source.Reply(_("To delete, type: \002%s%s %s %d\002"), Config->StrictPrivmsg.c_str(), bi->nick.c_str(), cmd.c_str(), index + 1);
source.Reply(_("To delete, type: \002%s %s %d\002"), bi->GetQueryCommand().c_str(), cmd.c_str(), index + 1);
}
source.Reply("%s", m->text.c_str());
+5 -1
View File
@@ -56,7 +56,11 @@ public:
if (result == MemoServService::MEMO_INVALID_TARGET)
source.Reply(_("\002%s\002 is not a registered unforbidden nick or channel."), nick.c_str());
else if (result == MemoServService::MEMO_TOO_FAST)
source.Reply(_("Please wait %lu seconds before using the %s command again."), Config->GetModule("memoserv")->Get<unsigned long>("senddelay"), source.command.c_str());
{
auto lastmemosend = source.GetUser() ? source.GetUser()->lastmemosend : 0;
auto waitperiod = (lastmemosend + Config->GetModule("memoserv")->Get<unsigned long>("senddelay")) - Anope::CurTime;
source.Reply(_("Please wait %s before using the %s command again."), Anope::Duration(waitperiod, source.GetAccount()).c_str(), source.command.c_str());
}
else if (result == MemoServService::MEMO_TARGET_FULL)
source.Reply(_("Sorry, %s currently has too many memos and cannot receive more."), nick.c_str());
else
+5 -1
View File
@@ -55,7 +55,11 @@ public:
else if (result == MemoServService::MEMO_INVALID_TARGET)
source.Reply(_("\002%s\002 is not a registered unforbidden nick or channel."), nick.c_str());
else if (result == MemoServService::MEMO_TOO_FAST)
source.Reply(_("Please wait %lu seconds before using the %s command again."), Config->GetModule("memoserv")->Get<unsigned long>("senddelay"), source.command.c_str());
{
auto lastmemosend = source.GetUser() ? source.GetUser()->lastmemosend : 0;
auto waitperiod = (lastmemosend + Config->GetModule("memoserv")->Get<unsigned long>("senddelay")) - Anope::CurTime;
source.Reply(_("Please wait %s before using the %s command again."), Anope::Duration(waitperiod, source.GetAccount()).c_str(), source.command.c_str());
}
else if (result == MemoServService::MEMO_TARGET_FULL)
source.Reply(_("Sorry, %s currently has too many memos and cannot receive more."), nick.c_str());
}
+2 -2
View File
@@ -232,8 +232,8 @@ public:
" LIMIT Sets the maximum number of memos you can\n"
" receive\n"
" \n"
"Type \002%s%s HELP %s \037option\037\002 for more information\n"
"on a specific option."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), source.command.c_str());
"Type \002%s HELP %s \037option\037\002 for more information\n"
"on a specific option."), source.service->GetQueryCommand().c_str(), source.command.c_str());
}
else if (subcommand.equals_ci("NOTIFY"))
source.Reply(_("Syntax: \002NOTIFY {ON | LOGON | NEW | MAIL | NOMAIL | OFF}\002\n"
+65 -30
View File
@@ -98,7 +98,7 @@ class NickServRelease final
public:
NickServRelease(Module *me, NickAlias *na, time_t delay)
: User(na->nick, Config->GetModule("nickserv")->Get<const Anope::string>("enforceruser", "user"), Config->GetModule("nickserv")->Get<const Anope::string>("enforcerhost", Me->GetName()), "", "", Me, "Services Enforcer", Anope::CurTime, "", IRCD->UID_Retrieve(), NULL)
: User(na->nick, Config->GetModule(me)->Get<const Anope::string>("enforceruser", "user"), Config->GetModule(me)->Get<const Anope::string>("enforcerhost", Me->GetName()), "", "", Me, "Services Enforcer", Anope::CurTime, "", {}, IRCD->UID_Retrieve(), NULL)
, Timer(me, delay)
, nick(na->nick)
{
@@ -140,12 +140,12 @@ class NickServCore final
{
collided.Unset(na);
new NickServHeld(this, na, Config->GetModule("nickserv")->Get<time_t>("releasetimeout", "1m"));
new NickServHeld(this, na, Config->GetModule(this)->Get<time_t>("releasetimeout", "1m"));
if (IRCD->CanSVSHold)
IRCD->SendSVSHold(na->nick, Config->GetModule("nickserv")->Get<time_t>("releasetimeout", "1m"));
IRCD->SendSVSHold(na->nick, Config->GetModule(this)->Get<time_t>("releasetimeout", "1m"));
else
new NickServRelease(this, na, Config->GetModule("nickserv")->Get<time_t>("releasetimeout", "1m"));
new NickServRelease(this, na, Config->GetModule(this)->Get<time_t>("releasetimeout", "1m"));
}
}
@@ -174,6 +174,24 @@ public:
OnShutdown();
}
bool IsGuestNick(const Anope::string &nick) const override
{
const auto guestnick = Config->GetModule(this)->Get<Anope::string>("guestnick", "Guest####");
if (guestnick.empty())
return false; // No guest nick.
const auto minlen = std::min(nick.length(), guestnick.length());
for (size_t idx = 0; idx < minlen; ++idx)
{
if (guestnick[idx] == '#' && !isdigit(nick[idx]))
return false;
if (Anope::tolower(guestnick[idx]) != Anope::tolower(nick[idx]))
return false;
}
return true;
}
void Validate(User *u) override
{
NickAlias *na = NickAlias::Find(u->nick);
@@ -195,7 +213,7 @@ public:
if (!na->nc->HasExt("KILL_IMMED"))
{
u->SendMessage(NickServ, NICK_IS_SECURE, Config->StrictPrivmsg.c_str(), NickServ->nick.c_str());
u->SendMessage(NickServ, NICK_IS_SECURE, NickServ->GetQueryCommand().c_str());
}
if (na->nc->HasExt("KILLPROTECT"))
{
@@ -238,30 +256,47 @@ public:
if (IRCD->CanSVSNick)
{
unsigned nicklen = IRCD->MaxNick;
const Anope::string &guestprefix = Config->GetModule("nickserv")->Get<const Anope::string>("guestnickprefix", "Guest");
auto guestnickok = false;
Anope::string guestnick;
int i = 0;
do
for (auto i = 0; i < 10; ++i)
{
guestnick = guestprefix + Anope::ToString(static_cast<uint16_t>(Anope::RandomNumber()));
if (guestnick.length() > nicklen)
guestnick = guestnick.substr(0, nicklen);
}
while (User::Find(guestnick) && i++ < 10);
guestnick.clear();
for (auto guestnickchr : Config->GetModule(this)->Get<Anope::string>("guestnick", "Guest####").substr(0, IRCD->MaxNick))
{
if (guestnickchr == '#')
guestnick.append(Anope::ToString(abs(Anope::RandomNumber()) % 10));
else
guestnick.push_back(guestnickchr);
}
if (i == 11)
u->Kill(*NickServ, "Services nickname-enforcer kill");
else
// A guest nick is valid if it is non-empty and is not in use.
if (!guestnick.empty() && !User::Find(guestnick, true))
{
guestnickok = true;
break;
}
}
// If we can't find a guest nick and the IRCd supports
// uids then we should use that as the backup guest
// nickname.
if (!guestnickok && IRCD->RequiresID)
{
guestnickok = true;
guestnick = u->GetUID();
}
if (guestnickok)
{
u->SendMessage(*NickServ, _("Your nickname is now being changed to \002%s\002"), guestnick.c_str());
IRCD->SendForceNickChange(u, guestnick, Anope::CurTime);
return;
}
}
else
u->Kill(*NickServ, "Services nickname-enforcer kill");
// We can't change the user's nickname or we can't find an
// acceptable guest nick, give them the boot.
u->Kill(*NickServ, "Enforcement of services protected nickname");
}
void Release(NickAlias *na) override
@@ -362,8 +397,8 @@ public:
u->SendMessage(NickServ, _("You must now supply an email for your nick.\n"
"This email will allow you to retrieve your password in\n"
"case you forget it."));
u->SendMessage(NickServ, _("Type \002%s%s SET EMAIL \037email\037\002 in order to set your email."),
Config->StrictPrivmsg.c_str(), NickServ->nick.c_str());
u->SendMessage(NickServ, _("Type \002%s SET EMAIL \037email\037\002 in order to set your email."),
NickServ->GetQueryCommand().c_str());
}
for (auto *c : collides)
@@ -400,7 +435,7 @@ public:
const NickAlias *na = NickAlias::Find(u->nick);
const Anope::string &unregistered_notice = Config->GetModule(this)->Get<const Anope::string>("unregistered_notice");
if (!Config->GetModule("nickserv")->Get<bool>("nonicknameownership") && !unregistered_notice.empty() && !na && !u->Account())
if (!Config->GetModule("nickserv")->Get<bool>("nonicknameownership") && !unregistered_notice.empty() && !na && !u->IsIdentified())
u->SendMessage(NickServ, unregistered_notice.replace_all_cs("%n", u->nick));
else if (na && !u->IsIdentified(true))
this->Validate(u);
@@ -465,15 +500,15 @@ public:
source.Reply(_("\002%s\002 allows you to register a nickname and\n"
"prevent others from using it. The following\n"
"commands allow for registration and maintenance of\n"
"nicknames; to use them, type \002%s%s \037command\037\002.\n"
"nicknames; to use them, type \002%s \037command\037\002.\n"
"For more information on a specific command, type\n"
"\002%s%s %s \037command\037\002.\n"), NickServ->nick.c_str(), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str(), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str(), source.command.c_str());
"\002%s %s \037command\037\002.\n"), NickServ->nick.c_str(), NickServ->GetQueryCommand().c_str(), NickServ->GetQueryCommand().c_str(), source.command.c_str());
else
source.Reply(_("\002%s\002 allows you to register an account.\n"
"The following commands allow for registration and maintenance of\n"
"accounts; to use them, type \002%s%s \037command\037\002.\n"
"accounts; to use them, type \002%s \037command\037\002.\n"
"For more information on a specific command, type\n"
"\002%s%s %s \037command\037\002.\n"), NickServ->nick.c_str(), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str(), Config->StrictPrivmsg.c_str(), NickServ->nick.c_str(), source.command.c_str());
"\002%s %s \037command\037\002.\n"), NickServ->nick.c_str(), NickServ->GetQueryCommand().c_str(), NickServ->GetQueryCommand().c_str(), source.command.c_str());
return EVENT_CONTINUE;
}
@@ -486,7 +521,7 @@ public:
"Services Operators can also drop any nickname without needing\n"
"to identify for the nick, and may view the access list for\n"
"any nickname."));
time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire", "90d");
time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire", "1y");
if (nickserv_expire >= 86400)
source.Reply(_(" \n"
"Accounts that are not used anymore are subject to\n"
@@ -554,7 +589,7 @@ public:
{
if (!na->nc->HasExt("UNCONFIRMED"))
{
time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire", "90d");
time_t nickserv_expire = Config->GetModule(this)->Get<time_t>("expire", "1y");
if (!na->HasExt("NS_NO_EXPIRE") && nickserv_expire && !Anope::NoExpire && (source.HasPriv("nickserv/auspex") || na->last_seen != Anope::CurTime))
info[_("Expires")] = Anope::strftime(na->last_seen + nickserv_expire, source.GetAccount());
}
+3
View File
@@ -425,6 +425,9 @@ public:
auto *cl = certs.Require(na->nc);
cl->AddCert(u->fingerprint);
auto *NickServ = Config->GetClient("NickServ");
u->SendMessage(NickServ, _("Your SSL certificate fingerprint \002%s\002 has been automatically added to your certificate list."), u->fingerprint.c_str());
}
EventReturn OnNickValidate(User *u, NickAlias *na) override
+2 -2
View File
@@ -72,8 +72,8 @@ public:
*code = Anope::Random(15);
}
source.Reply(CONFIRM_DROP, na->nick.c_str(), Config->StrictPrivmsg.c_str(),
source.service->nick.c_str(), na->nick.c_str(), code->c_str());
source.Reply(CONFIRM_DROP, na->nick.c_str(), source.service->GetQueryCommand().c_str(),
na->nick.c_str(), code->c_str());
return;
}
+8 -8
View File
@@ -12,6 +12,8 @@
#include "module.h"
#include "modules/ns_cert.h"
static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
class NSGroupRequest final
: public IdentifyRequest
{
@@ -142,13 +144,15 @@ public:
}
NickAlias *target, *na = NickAlias::Find(source.GetNick());
const Anope::string &guestnick = Config->GetModule("nickserv")->Get<const Anope::string>("guestnickprefix", "Guest");
time_t reg_delay = Config->GetModule("nickserv")->Get<time_t>("regdelay");
unsigned maxaliases = Config->GetModule(this->owner)->Get<unsigned>("maxaliases");
if (!(target = NickAlias::Find(nick)))
source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
else if (user && Anope::CurTime < user->lastnickreg + reg_delay)
source.Reply(_("Please wait %lu seconds before using the GROUP command again."), (unsigned long)(reg_delay + user->lastnickreg) - Anope::CurTime);
{
auto waitperiod = (unsigned long)(reg_delay + user->lastnickreg) - Anope::CurTime;
source.Reply(_("Please wait %s before using the GROUP command again."), Anope::Duration(waitperiod, source.GetAccount()).c_str());
}
else if (target->nc->HasExt("NS_SUSPENDED"))
{
Log(LOG_COMMAND, source, this) << "and tried to group to SUSPENDED nick " << target->nick;
@@ -162,12 +166,8 @@ public:
source.Reply(NICK_IDENTIFY_REQUIRED);
else if (maxaliases && target->nc->aliases->size() >= maxaliases && !target->nc->IsServicesOper())
source.Reply(_("There are too many nicks in your group."));
else if (source.GetNick().length() <= guestnick.length() + 7 &&
source.GetNick().length() >= guestnick.length() + 1 &&
!source.GetNick().find_ci(guestnick) && !source.GetNick().substr(guestnick.length()).find_first_not_of("1234567890"))
{
else if (nickserv && nickserv->IsGuestNick(source.GetNick()))
source.Reply(NICK_CANNOT_BE_REGISTERED, source.GetNick().c_str());
}
else
{
bool ok = false;
@@ -356,7 +356,7 @@ public:
for (const auto &reply : replies)
source.Reply(reply);
source.Reply(_("%zu nickname(s) in the group."), nc->aliases->size());
source.Reply(nc->aliases->size(), N_("%zu nickname in the group.", "%zu nicknames in the group."), nc->aliases->size());
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
+1 -1
View File
@@ -84,7 +84,7 @@ public:
return;
}
if (u->Account() && na && u->Account() == na->nc)
if (u->IsIdentified() && na && u->Account() == na->nc)
{
source.Reply(_("You are already identified."));
return;
+9 -12
View File
@@ -13,6 +13,8 @@
static bool SendRegmail(User *u, const NickAlias *na, BotInfo *bi);
static ServiceReference<NickServService> nickserv("NickServService", "NickServ");
class CommandNSConfirm final
: public Command
{
@@ -133,7 +135,6 @@ public:
{
User *u = source.GetUser();
Anope::string u_nick = source.GetNick();
size_t nicklen = u_nick.length();
Anope::string pass = params[0];
Anope::string email = params.size() > 1 ? params[1] : "";
const Anope::string &nsregister = Config->GetModule(this->owner)->Get<const Anope::string>("registration");
@@ -154,18 +155,13 @@ public:
time_t reg_delay = Config->GetModule("nickserv")->Get<time_t>("regdelay");
if (u && !u->HasMode("OPER") && nickregdelay && Anope::CurTime - u->timestamp < nickregdelay)
{
source.Reply(_("You must have been using this nick for at least %lu seconds to register."),
(unsigned long)nickregdelay);
auto waitperiod = (u->timestamp + nickregdelay) - Anope::CurTime;
source.Reply(_("You must wait %s before registering your nick."),
Anope::Duration(waitperiod, source.GetAccount()).c_str());
return;
}
/* Prevent "Guest" nicks from being registered. -TheShadow */
/* Guest nick can now have a series of between 1 and 7 digits.
* --lara
*/
const Anope::string &guestnick = Config->GetModule("nickserv")->Get<const Anope::string>("guestnickprefix", "Guest");
if (nicklen <= guestnick.length() + 7 && nicklen >= guestnick.length() + 1 && !u_nick.find_ci(guestnick) && u_nick.substr(guestnick.length()).find_first_not_of("1234567890") == Anope::string::npos)
if (nickserv && nickserv->IsGuestNick(u_nick))
{
source.Reply(NICK_CANNOT_BE_REGISTERED, u_nick.c_str());
return;
@@ -202,8 +198,9 @@ public:
this->OnSyntaxError(source, "");
else if (u && Anope::CurTime < u->lastnickreg + reg_delay)
{
source.Reply(_("Please wait %lu seconds before using the REGISTER command again."),
(unsigned long)(u->lastnickreg + reg_delay) - Anope::CurTime);
auto waitperiod = (unsigned long)(u->lastnickreg + reg_delay) - Anope::CurTime;
source.Reply(_("Please wait %s before using the REGISTER command again."),
Anope::Duration(waitperiod, source.GetAccount()).c_str());
}
else if (NickAlias::Find(u_nick) != NULL)
source.Reply(NICK_ALREADY_REGISTERED, u_nick.c_str());
+9 -275
View File
@@ -17,7 +17,7 @@ class CommandNSSet final
public:
CommandNSSet(Module *creator) : Command(creator, "nickserv/set", 1, 3)
{
this->SetDesc(_("Set options, including kill protection"));
this->SetDesc(_("Set nickname options and information"));
this->SetSyntax(_("\037option\037 \037parameters\037"));
}
@@ -57,8 +57,8 @@ public:
}
}
source.Reply(_("Type \002%s%s HELP %s \037option\037\002 for more information\n"
"on a specific option."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), this_name.c_str());
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information\n"
"on a specific option."), source.service->GetQueryCommand().c_str(), this_name.c_str());
return true;
}
@@ -100,9 +100,9 @@ public:
}
}
source.Reply(_("Type \002%s%s HELP %s \037option\037\002 for more information\n"
source.Reply(_("Type \002%s HELP %s \037option\037\002 for more information\n"
"on a specific option. The options will be set on the given\n"
"\037nickname\037."), Config->StrictPrivmsg.c_str(), source.service->nick.c_str(), this_name.c_str());
"\037nickname\037."), source.service->GetQueryCommand().c_str(), this_name.c_str());
return true;
}
};
@@ -752,252 +752,6 @@ public:
}
};
class CommandNSSetKill
: public Command
{
public:
CommandNSSetKill(Module *creator, const Anope::string &sname = "nickserv/set/kill", size_t min = 1) : Command(creator, sname, min, min + 1)
{
this->SetDesc(_("Turn protection on or off"));
this->SetSyntax("{ON | QUICK | IMMED | OFF}");
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
{
if (Anope::ReadOnly)
{
source.Reply(READ_ONLY_MODE);
return;
}
if (Config->GetModule("nickserv")->Get<bool>("nonicknameownership"))
{
source.Reply(_("This command may not be used on this network because nickname ownership is disabled."));
return;
}
const NickAlias *na = NickAlias::Find(user);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
return;
}
NickCore *nc = na->nc;
EventReturn MOD_RESULT;
FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
if (MOD_RESULT == EVENT_STOP)
return;
if (param.equals_ci("ON"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill on for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002."), nc->display.c_str());
}
else if (param.equals_ci("QUICK"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Extend<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill quick for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002, with a reduced delay."), nc->display.c_str());
}
else if (param.equals_ci("IMMED"))
{
if (Config->GetModule(this->owner)->Get<bool>("allowkillimmed"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Extend<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill immed for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002, with no delay."), nc->display.c_str());
}
else
source.Reply(_("The \002IMMED\002 option is not available on this network."));
}
else if (param.equals_ci("OFF"))
{
nc->Shrink<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable kill for " << nc->display;
source.Reply(_("Protection is now \002off\002 for \002%s\002."), nc->display.c_str());
}
else
this->OnSyntaxError(source, "KILL");
return;
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, source.nc->display, params[0]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Turns the automatic protection option for your nick\n"
"on or off. With protection on, if another user\n"
"tries to take your nick, they will be given one minute to\n"
"change to another nick, after which %s will forcibly change\n"
"their nick.\n"
" \n"
"If you select \002QUICK\002, the user will be given only 20 seconds\n"
"to change nicks instead of the usual 60. If you select\n"
"\002IMMED\002, the user's nick will be changed immediately \037without\037 being\n"
"warned first or given a chance to change their nick; please\n"
"do not use this option unless necessary. Also, your\n"
"network's administrators may have disabled this option."), source.service->nick.c_str());
return true;
}
};
class CommandNSSASetKill final
: public CommandNSSetKill
{
public:
CommandNSSASetKill(Module *creator) : CommandNSSetKill(creator, "nickserv/saset/kill", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 {ON | QUICK | IMMED | OFF}"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, params[0], params[1]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Turns the automatic protection option for the nick\n"
"on or off. With protection on, if another user\n"
"tries to take the nick, they will be given one minute to\n"
"change to another nick, after which %s will forcibly change\n"
"their nick.\n"
" \n"
"If you select \002QUICK\002, the user will be given only 20 seconds\n"
"to change nicks instead of the usual 60. If you select\n"
"\002IMMED\002, the user's nick will be changed immediately \037without\037 being\n"
"warned first or given a chance to change their nick; please\n"
"do not use this option unless necessary. Also, your\n"
"network's administrators may have disabled this option."), source.service->nick.c_str());
return true;
}
};
class CommandNSSetMessage
: public Command
{
public:
CommandNSSetMessage(Module *creator, const Anope::string &sname = "nickserv/set/message", size_t min = 1) : Command(creator, sname, min, min + 1)
{
this->SetDesc(_("Change the communication method of services"));
this->SetSyntax("{ON | OFF}");
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
{
if (Anope::ReadOnly)
{
source.Reply(READ_ONLY_MODE);
return;
}
const NickAlias *na = NickAlias::Find(user);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
return;
}
NickCore *nc = na->nc;
if (!Config->GetBlock("options")->Get<bool>("useprivmsg"))
{
source.Reply(_("You cannot %s on this network."), source.command.c_str());
return;
}
EventReturn MOD_RESULT;
FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
if (MOD_RESULT == EVENT_STOP)
return;
if (param.equals_ci("ON"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable " << source.command << " for " << nc->display;
nc->Extend<bool>("MSG");
source.Reply(_("Services will now reply to \002%s\002 with \002messages\002."), nc->display.c_str());
}
else if (param.equals_ci("OFF"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable " << source.command << " for " << nc->display;
nc->Shrink<bool>("MSG");
source.Reply(_("Services will now reply to \002%s\002 with \002notices\002."), nc->display.c_str());
}
else
this->OnSyntaxError(source, "MSG");
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, source.nc->display, params[0]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
Anope::string cmd = source.command;
size_t i = cmd.find_last_of(' ');
if (i != Anope::string::npos)
cmd = cmd.substr(i + 1);
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows you to choose the way services are communicating with\n"
"you. With \002%s\002 set, services will use messages, else they'll\n"
"use notices."), cmd.upper().c_str());
return true;
}
void OnServHelp(CommandSource &source) override
{
if (Config->GetBlock("options")->Get<bool>("useprivmsg"))
Command::OnServHelp(source);
}
};
class CommandNSSASetMessage final
: public CommandNSSetMessage
{
public:
CommandNSSASetMessage(Module *creator) : CommandNSSetMessage(creator, "nickserv/saset/message", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 {ON | OFF}"));
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows you to choose the way services are communicating with\n"
"the given user. With \002MSG\002 set, services will use messages,\n"
"else they'll use notices."));
return true;
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, params[0], params[1]);
}
};
class CommandNSSASetNoexpire final
: public Command
{
@@ -1072,19 +826,13 @@ class NSSet final
CommandNSSetKeepModes commandnssetkeepmodes;
CommandNSSASetKeepModes commandnssasetkeepmodes;
CommandNSSetKill commandnssetkill;
CommandNSSASetKill commandnssasetkill;
CommandNSSetMessage commandnssetmessage;
CommandNSSASetMessage commandnssasetmessage;
CommandNSSetPassword commandnssetpassword;
CommandNSSASetPassword commandnssasetpassword;
CommandNSSASetNoexpire commandnssasetnoexpire;
SerializableExtensibleItem<bool> autoop, neverop, killprotect, kill_quick, kill_immed,
message, noexpire;
SerializableExtensibleItem<bool> autoop, neverop, noexpire;
struct KeepModes final
: SerializableExtensibleItem<bool>
@@ -1144,19 +892,13 @@ public:
commandnssetdisplay(this), commandnssasetdisplay(this),
commandnssetemail(this), commandnssasetemail(this),
commandnssetkeepmodes(this), commandnssasetkeepmodes(this),
commandnssetkill(this), commandnssasetkill(this),
commandnssetmessage(this), commandnssasetmessage(this),
commandnssetpassword(this), commandnssasetpassword(this),
commandnssasetnoexpire(this),
autoop(this, "AUTOOP"), neverop(this, "NEVEROP"),
killprotect(this, "KILLPROTECT"), kill_quick(this, "KILL_QUICK"),
kill_immed(this, "KILL_IMMED"), message(this, "MSG"),
noexpire(this, "NS_NO_EXPIRE"),
keep_modes(this, "NS_KEEP_MODES"), ns_set_email(this, "ns_set_email")
{
}
EventReturn OnPreCommand(CommandSource &source, Command *command, std::vector<Anope::string> &params) override
@@ -1187,7 +929,7 @@ public:
if (chan->ci)
{
/* Only give modes if autoop is set */
give_modes &= !user->Account() || autoop.HasExt(user->Account());
give_modes &= !user->IsIdentified() || autoop.HasExt(user->Account());
}
}
@@ -1202,14 +944,6 @@ public:
if (!show_hidden)
return;
if (kill_immed.HasExt(na->nc))
info.AddOption(_("Immediate protection"));
else if (kill_quick.HasExt(na->nc))
info.AddOption(_("Quick protection"));
else if (killprotect.HasExt(na->nc))
info.AddOption(_("Protection"));
if (message.HasExt(na->nc))
info.AddOption(_("Message mode"));
if (autoop.HasExt(na->nc))
info.AddOption(_("Auto-op"));
if (neverop.HasExt(na->nc))
@@ -1222,13 +956,13 @@ public:
void OnUserModeSet(const MessageSource &setter, User *u, const Anope::string &mname) override
{
if (u->Account() && setter.GetUser() == u)
if (u->IsIdentified() && setter.GetUser() == u)
u->Account()->last_modes = u->GetModeList();
}
void OnUserModeUnset(const MessageSource &setter, User *u, const Anope::string &mname) override
{
if (u->Account() && setter.GetUser() == u)
if (u->IsIdentified() && setter.GetUser() == u)
u->Account()->last_modes = u->GetModeList();
}
+189
View File
@@ -0,0 +1,189 @@
/* NickServ core functions
*
* (C) 2003-2024 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*/
#include "module.h"
class CommandNSSetKill
: public Command
{
public:
CommandNSSetKill(Module *creator, const Anope::string &sname = "nickserv/set/kill", size_t min = 1)
: Command(creator, sname, min, min + 1)
{
this->SetDesc(_("Turn protection on or off"));
this->SetSyntax("{ON | QUICK | IMMED | OFF}");
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
{
if (Anope::ReadOnly)
{
source.Reply(READ_ONLY_MODE);
return;
}
if (Config->GetModule("nickserv")->Get<bool>("nonicknameownership"))
{
source.Reply(_("This command may not be used on this network because nickname ownership is disabled."));
return;
}
const NickAlias *na = NickAlias::Find(user);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
return;
}
NickCore *nc = na->nc;
EventReturn MOD_RESULT;
FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
if (MOD_RESULT == EVENT_STOP)
return;
if (param.equals_ci("ON"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill on for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002."), nc->display.c_str());
}
else if (param.equals_ci("QUICK"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Extend<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill quick for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002, with a reduced delay."), nc->display.c_str());
}
else if (param.equals_ci("IMMED"))
{
if (Config->GetModule(this->owner)->Get<bool>("allowkillimmed"))
{
nc->Extend<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Extend<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to set kill immed for " << nc->display;
source.Reply(_("Protection is now \002on\002 for \002%s\002, with no delay."), nc->display.c_str());
}
else
source.Reply(_("The \002IMMED\002 option is not available on this network."));
}
else if (param.equals_ci("OFF"))
{
nc->Shrink<bool>("KILLPROTECT");
nc->Shrink<bool>("KILL_QUICK");
nc->Shrink<bool>("KILL_IMMED");
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable kill for " << nc->display;
source.Reply(_("Protection is now \002off\002 for \002%s\002."), nc->display.c_str());
}
else
this->OnSyntaxError(source, "KILL");
return;
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, source.nc->display, params[0]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Turns the automatic protection option for your nick\n"
"on or off. With protection on, if another user\n"
"tries to take your nick, they will be given one minute to\n"
"change to another nick, after which %s will forcibly change\n"
"their nick.\n"
" \n"
"If you select \002QUICK\002, the user will be given only 20 seconds\n"
"to change nicks instead of the usual 60. If you select\n"
"\002IMMED\002, the user's nick will be changed immediately \037without\037 being\n"
"warned first or given a chance to change their nick; please\n"
"do not use this option unless necessary. Also, your\n"
"network's administrators may have disabled this option."), source.service->nick.c_str());
return true;
}
};
class CommandNSSASetKill final
: public CommandNSSetKill
{
public:
CommandNSSASetKill(Module *creator)
: CommandNSSetKill(creator, "nickserv/saset/kill", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 {ON | QUICK | IMMED | OFF}"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, params[0], params[1]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Turns the automatic protection option for the nick\n"
"on or off. With protection on, if another user\n"
"tries to take the nick, they will be given one minute to\n"
"change to another nick, after which %s will forcibly change\n"
"their nick.\n"
" \n"
"If you select \002QUICK\002, the user will be given only 20 seconds\n"
"to change nicks instead of the usual 60. If you select\n"
"\002IMMED\002, the user's nick will be changed immediately \037without\037 being\n"
"warned first or given a chance to change their nick; please\n"
"do not use this option unless necessary. Also, your\n"
"network's administrators may have disabled this option."), source.service->nick.c_str());
return true;
}
};
class NSSetKill final
: public Module
{
private:
CommandNSSetKill commandnssetkill;
CommandNSSASetKill commandnssasetkill;
SerializableExtensibleItem<bool> killprotect, kill_quick, kill_immed;
public:
NSSetKill(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandnssetkill(this)
, commandnssasetkill(this)
, killprotect(this, "KILLPROTECT")
, kill_quick(this, "KILL_QUICK")
, kill_immed(this, "KILL_IMMED")
{
}
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) override
{
if (!show_hidden)
return;
if (kill_immed.HasExt(na->nc))
info.AddOption(_("Immediate protection"));
else if (kill_quick.HasExt(na->nc))
info.AddOption(_("Quick protection"));
else if (killprotect.HasExt(na->nc))
info.AddOption(_("Protection"));
}
};
MODULE_INIT(NSSetKill)
+43 -32
View File
@@ -14,9 +14,13 @@
class CommandNSSetLanguage
: public Command
{
protected:
Anope::map<Anope::string> &languages;
public:
CommandNSSetLanguage(Module *creator, const Anope::string &sname = "nickserv/set/language", size_t min = 1)
CommandNSSetLanguage(Module *creator, Anope::map<Anope::string> &langs, const Anope::string &sname = "nickserv/set/language", size_t min = 1)
: Command(creator, sname, min, min + 1)
, languages(langs)
{
this->SetDesc(_("Set the language services will use when messaging you"));
this->SetSyntax(_("\037language\037"));
@@ -43,27 +47,35 @@ public:
if (MOD_RESULT == EVENT_STOP)
return;
if (param != "en_US")
auto lang = languages.end();
for (auto it = languages.begin(); it != languages.end(); ++it)
{
for (unsigned j = 0; j < Language::Languages.size(); ++j)
auto &[langcode, langname] = *it;
if (langcode.find_ci(param) != 0)
continue; // Language does not match.
if (lang != languages.end())
{
if (Language::Languages[j] == param)
break;
else if (j + 1 == Language::Languages.size())
{
this->OnSyntaxError(source, "");
return;
}
source.Reply(_("Multiple languages matched \002%s\002. Please be more specific."), param.c_str());
return;
}
lang = it;
}
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the language of " << nc->display << " to " << param;
if (lang == languages.end())
{
this->OnSyntaxError(source, "");
return;
}
nc->language = param;
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to change the language of " << nc->display << " to " << lang->first;
nc->language = lang->first;
if (source.GetAccount() == nc)
source.Reply(_("Language changed to \002English\002."));
source.Reply(_("Language changed to \002%s\002."), lang->second.c_str());
else
source.Reply(_("Language for \002%s\002 changed to \002%s\002."), nc->display.c_str(), Language::Translate(param.c_str(), _("English")));
source.Reply(_("Language for \002%s\002 changed to \002%s\002."), nc->display.c_str(), lang->second.c_str());
}
void Execute(CommandSource &source, const std::vector<Anope::string> &param) override
@@ -80,13 +92,8 @@ public:
"\037language\037 should be chosen from the following list of\n"
"supported languages:"));
source.Reply(" en_US (English)");
for (const auto &language : Language::Languages)
{
const Anope::string &langname = Language::Translate(language.c_str(), _("English"));
if (langname != "English")
source.Reply(" %s (%s)", language.c_str(), langname.c_str());
}
for (const auto &[langcode, langname] : languages)
source.Reply(" %s (%s)", langcode.c_str(), langname.c_str());
return true;
}
@@ -96,8 +103,8 @@ class CommandNSSASetLanguage final
: public CommandNSSetLanguage
{
public:
CommandNSSASetLanguage(Module *creator)
: CommandNSSetLanguage(creator, "nickserv/saset/language", 2)
CommandNSSASetLanguage(Module *creator, Anope::map<Anope::string> &langs)
: CommandNSSetLanguage(creator, langs, "nickserv/saset/language", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 \037language\037"));
@@ -116,13 +123,10 @@ public:
"the given user (for example, when responding to a command they send).\n"
"\037language\037 should be chosen from the following list of\n"
"supported languages:"));
source.Reply(" en_US (English)");
for (const auto &language : Language::Languages)
{
const Anope::string &langname = Language::Translate(language.c_str(), _("English"));
if (langname != "English")
source.Reply(" %s (%s)", language.c_str(), langname.c_str());
}
for (const auto &[langcode, langname] : languages)
source.Reply(" %s (%s)", langcode.c_str(), langname.c_str());
return true;
}
};
@@ -133,16 +137,23 @@ class NSSetLanguage final
private:
CommandNSSetLanguage commandnssetlanguage;
CommandNSSASetLanguage commandnssasetlanguage;
Anope::map<Anope::string> languages;
public:
NSSetLanguage(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandnssetlanguage(this)
, commandnssasetlanguage(this)
, commandnssetlanguage(this, languages)
, commandnssasetlanguage(this, languages)
{
#ifndef HAVE_LOCALIZATION
throw ModuleException("Anope was not built with localization support");
#endif
// Build a list of languages. This only needs to happen once as we
// only load the languages on boot.
languages.emplace("en_US.UTF-8", "English");
for (const auto &language : Language::Languages)
languages.emplace(language, Language::Translate(language.c_str(), _("English")));
}
};
+137
View File
@@ -0,0 +1,137 @@
/* NickServ core functions
*
* (C) 2003-2024 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*/
#include "module.h"
class CommandNSSetMessage
: public Command
{
public:
CommandNSSetMessage(Module *creator, const Anope::string &sname = "nickserv/set/message", size_t min = 1)
: Command(creator, sname, min, min + 1)
{
this->SetDesc(_("Change the communication method of services"));
this->SetSyntax("{ON | OFF}");
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param)
{
if (Anope::ReadOnly)
{
source.Reply(READ_ONLY_MODE);
return;
}
const NickAlias *na = NickAlias::Find(user);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, user.c_str());
return;
}
NickCore *nc = na->nc;
EventReturn MOD_RESULT;
FOREACH_RESULT(OnSetNickOption, MOD_RESULT, (source, this, nc, param));
if (MOD_RESULT == EVENT_STOP)
return;
if (param.equals_ci("ON"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to enable " << source.command << " for " << nc->display;
nc->Extend<bool>("MSG");
source.Reply(_("Services will now reply to \002%s\002 with \002messages\002."), nc->display.c_str());
}
else if (param.equals_ci("OFF"))
{
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to disable " << source.command << " for " << nc->display;
nc->Shrink<bool>("MSG");
source.Reply(_("Services will now reply to \002%s\002 with \002notices\002."), nc->display.c_str());
}
else
this->OnSyntaxError(source, "MSG");
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, source.nc->display, params[0]);
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
Anope::string cmd = source.command;
size_t i = cmd.find_last_of(' ');
if (i != Anope::string::npos)
cmd = cmd.substr(i + 1);
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows you to choose the way services are communicating with\n"
"you. With \002%s\002 set, services will use messages, else they'll\n"
"use notices."), cmd.upper().c_str());
return true;
}
};
class CommandNSSASetMessage final
: public CommandNSSetMessage
{
public:
CommandNSSASetMessage(Module *creator) : CommandNSSetMessage(creator, "nickserv/saset/message", 2)
{
this->ClearSyntax();
this->SetSyntax(_("\037nickname\037 {ON | OFF}"));
}
bool OnHelp(CommandSource &source, const Anope::string &) override
{
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("Allows you to choose the way services are communicating with\n"
"the given user. With \002MSG\002 set, services will use messages,\n"
"else they'll use notices."));
return true;
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
{
this->Run(source, params[0], params[1]);
}
};
class NSSetMessage final
: public Module
{
private:
CommandNSSetMessage commandnssetmessage;
CommandNSSASetMessage commandnssasetmessage;
SerializableExtensibleItem<bool> message;
public:
NSSetMessage(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandnssetmessage(this)
, commandnssasetmessage(this)
, message(this, "MSG")
{
}
void OnNickInfo(CommandSource &source, NickAlias *na, InfoFormatter &info, bool show_hidden) override
{
if (!show_hidden)
return;
if (message.HasExt(na->nc))
info.AddOption(_("Message mode"));
}
};
MODULE_INIT(NSSetMessage)
+1 -1
View File
@@ -292,7 +292,7 @@ public:
delete na;
}
source.Reply(_("\002%d\002 nickname(s) dropped."), na_matches);
source.Reply(na_matches, N_("\002%d\002 nickname dropped.", "\002%d\002 nicknames dropped."), na_matches);
break;
}
case FT_CHAN:
+7 -10
View File
@@ -312,12 +312,8 @@ struct IRCDMessageMode final
Channel *c = Channel::Find(params[0]);
auto ts = IRCD->ExtractTimestamp(params[1]);
Anope::string modes = params[2];
for (unsigned int i = 3; i < params.size(); ++i)
modes += " " + params[i];
if (c)
c->SetModesInternal(source, modes, ts);
c->SetModesInternal(source, params[2], { params.begin() + 3, params.end() }, ts);
}
else
{
@@ -400,11 +396,12 @@ struct IRCDMessageSJoin final
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override
{
Anope::string modes;
std::vector<Anope::string> modeparams;
if (params.size() >= 4)
for (unsigned i = 2; i < params.size(); ++i)
modes += " " + params[i];
if (!modes.empty())
modes.erase(modes.begin());
{
modes = params[2];
modeparams = { params.begin() + 3, params.end() };
}
std::list<Message::Join::SJoinUser> users;
@@ -445,7 +442,7 @@ struct IRCDMessageSJoin final
}
auto ts = IRCD->ExtractTimestamp(params[0]);
Message::Join::SJoin(source, params[1], ts, modes, users);
Message::Join::SJoin(source, params[1], ts, modes, modeparams, users);
}
};
+2 -14
View File
@@ -547,14 +547,6 @@ struct IRCDMessageSJoin final
/* :0MC SJOIN 1654877335 #nether +nt :@0MCAAAAAB +0MCAAAAAC */
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override
{
Anope::string modes;
for (unsigned i = 2; i < params.size() - 1; ++i)
modes += " " + params[i];
if (!modes.empty())
modes.erase(modes.begin());
std::list<Message::Join::SJoinUser> users;
spacesepstream sep(params[params.size() - 1]);
@@ -582,7 +574,7 @@ struct IRCDMessageSJoin final
}
auto ts = IRCD->ExtractTimestamp(params[0]);
Message::Join::SJoin(source, params[1], ts, modes, users);
Message::Join::SJoin(source, params[1], ts, params[2], { params.begin() + 3, params.end() - 1 }, users);
}
};
@@ -637,13 +629,9 @@ struct IRCDMessageTMode final
{
auto ts = IRCD->ExtractTimestamp(params[0]);
Channel *c = Channel::Find(params[1]);
Anope::string modes = params[2];
for (unsigned i = 3; i < params.size(); ++i)
modes += " " + params[i];
if (c)
c->SetModesInternal(source, modes, ts);
c->SetModesInternal(source, params[2], { params.begin() + 3, params.end() }, ts);
}
};
+47 -65
View File
@@ -27,6 +27,9 @@ struct SASLUser final
namespace
{
/** Whether we should send extbans using their named form. */
bool named_extbans = false;
// The SID of a server we are waiting to squit.
Anope::string rsquit_id;
@@ -102,7 +105,7 @@ class InspIRCdProto final
private:
static Anope::string GetAccountNicks(NickAlias* na)
{
if (!na)
if (!na || Config->GetModule("nickserv")->Get<bool>("nonicknameownership"))
return {};
Anope::string nicks;
@@ -637,6 +640,17 @@ public:
}
}
void SendOper(User *u) override
{
if (spanningtree_proto_ver < 1206)
return; // We can't force an oper on this version.
const Anope::map<Anope::string> tags = {
{ "~automatic", "" },
};
Uplink::Send(tags, "SVSOPER", u->GetUID(), u->Account()->o->ot->GetName());
}
bool IsExtbanValid(const Anope::string &mask) override
{
bool inverted;
@@ -712,7 +726,8 @@ namespace InspIRCdExtBan
ChannelMode *Wrap(Anope::string &param) override
{
param = Anope::string(xbchar) + ":" + param;
auto xbprefix = named_extbans || !xbchar ? xbname : Anope::string(xbchar);
param = xbprefix + ":" + param;
return ChannelModeVirtual<ChannelModeList>::Wrap(param);
}
@@ -746,10 +761,7 @@ namespace InspIRCdExtBan
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(2);
return Entry(this->name, real_mask).Matches(u);
return Entry(this->name, e->GetMask()).Matches(u);
}
};
@@ -764,10 +776,7 @@ namespace InspIRCdExtBan
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string channel = mask.substr(2);
auto channel = e->GetMask();
ChannelMode *cm = NULL;
if (channel[0] != '#')
{
@@ -802,10 +811,7 @@ namespace InspIRCdExtBan
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(2);
return u->IsIdentified() && real_mask.equals_ci(u->Account()->display);
return u->IsIdentified() && e->GetMask().equals_ci(u->Account()->display);
}
};
@@ -820,9 +826,7 @@ namespace InspIRCdExtBan
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(2);
return Anope::Match(u->realname, real_mask);
return Anope::Match(u->realname, e->GetMask());
}
};
@@ -837,9 +841,7 @@ namespace InspIRCdExtBan
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(2);
return Anope::Match(u->server->GetName(), real_mask);
return Anope::Match(u->server->GetName(), e->GetMask());
}
};
@@ -854,9 +856,7 @@ namespace InspIRCdExtBan
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(2);
return !u->fingerprint.empty() && Anope::Match(u->fingerprint, real_mask);
return !u->fingerprint.empty() && Anope::Match(u->fingerprint, e->GetMask());
}
};
@@ -871,9 +871,7 @@ namespace InspIRCdExtBan
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(2);
return !u->Account() && Entry("BAN", real_mask).Matches(u);
return !u->Account() && Entry(this->base, e->GetMask()).Matches(u);
}
};
@@ -892,9 +890,7 @@ namespace InspIRCdExtBan
if (!opertype)
return false; // Not an operator.
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(2);
return Anope::Match(opertype->replace_all_cs(' ', '_'), real_mask);
return Anope::Match(opertype->replace_all_cs(' ', '_'), e->GetMask());
}
};
}
@@ -1080,19 +1076,25 @@ struct IRCDMessageCapab final
static bool ParseExtBan(const Anope::string &token, ExtBanInfo &extban)
{
// acting:foo=f matching:foo=f
// A B A B
// acting:foo=f matching:bar=b matching:baz
// A B A B A
auto a = token.find(':');
if (a == Anope::string::npos)
return false;
auto b = token.find(':', a + 1);
auto b = token.find('=', a + 1);
if (b == Anope::string::npos)
return false;
{
// ExtBan only has a name.
extban.name = token.substr(a + 1);
}
else
{
// ExtBan has a name and letter.
extban.name = token.substr(a + 1, b - a - 1);
extban.letter = token[b + 1];
}
extban.type = token.substr(0, a);
extban.name = token.substr(a + 1, b - a - 1);
extban.letter = token[b + 1];
if (Anope::ProtocolDebug)
Log(LOG_DEBUG) << "Parsed extban: type=" << extban.type << " name=" << extban.name << " letter=" << extban.letter;
@@ -1562,6 +1564,8 @@ struct IRCDMessageCapab final
auto [tokname, tokvalue] = ParseCapability(capab);
if (tokname == "CHALLENGE")
challenge = tokvalue;
if (tokname == "EXTBANFORMAT")
named_extbans = tokvalue.equals_ci("any") || tokvalue.equals_ci("name");
else if (tokname == "MAXCHANNEL")
IRCD->MaxChannel = Anope::Convert<size_t>(tokvalue, IRCD->MaxChannel);
else if (tokname == "MAXHOST")
@@ -2045,15 +2049,6 @@ struct IRCDMessageFJoin final
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override
{
Anope::string modes;
if (params.size() >= 3)
{
for (unsigned i = 2; i < params.size() - 1; ++i)
modes += " " + params[i];
if (!modes.empty())
modes.erase(modes.begin());
}
std::list<Message::Join::SJoinUser> users;
spacesepstream sep(params[params.size() - 1]);
@@ -2091,7 +2086,7 @@ struct IRCDMessageFJoin final
}
auto ts = IRCD->ExtractTimestamp(params[1]);
Message::Join::SJoin(source, params[0], ts, modes, users);
Message::Join::SJoin(source, params[0], ts, params[2], { params.begin() + 3, params.end() - 1 }, users);
}
};
@@ -2103,15 +2098,10 @@ struct IRCDMessageFMode final
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override
{
/* :source FMODE #test 12345678 +nto foo */
Anope::string modes = params[2];
for (unsigned n = 3; n < params.size(); ++n)
modes += " " + params[n];
Channel *c = Channel::Find(params[0]);
auto ts = IRCD->ExtractTimestamp(params[1]);
if (c)
c->SetModesInternal(source, modes, ts);
c->SetModesInternal(source, params[2], { params.begin() + 3, params.end() }, ts);
}
};
@@ -2144,12 +2134,12 @@ struct IRCDMessageIdle final
{
BotInfo *bi = BotInfo::Find(params[0]);
if (bi)
Uplink::Send(bi, "IDLE", source.GetSource(), Anope::StartTime, Anope::CurTime - bi->lastmsg);
Uplink::Send(bi, "IDLE", source.GetSource(), bi->signon, Anope::CurTime - bi->lastmsg);
else
{
User *u = User::Find(params[0]);
if (u && u->server == Me)
Uplink::Send(u, "IDLE", source.GetSource(), Anope::StartTime, 0);
Uplink::Send(u, "IDLE", source.GetSource(), u->signon, 0);
}
}
};
@@ -2187,7 +2177,7 @@ struct IRCDMessageIJoin final
std::list<Message::Join::SJoinUser> users;
users.push_back(user);
Message::Join::SJoin(source, params[0], chants, "", users);
Message::Join::SJoin(source, params[0], chants, "", {}, users);
}
};
@@ -2239,12 +2229,8 @@ struct IRCDMessageMode final
{
Channel *c = Channel::Find(params[0]);
Anope::string modes = params[1];
for (unsigned n = 2; n < params.size(); ++n)
modes += " " + params[n];
if (c)
c->SetModesInternal(source, modes);
c->SetModesInternal(source, params[2], { params.begin() + 3, params.end() });
}
else
{
@@ -2404,10 +2390,6 @@ struct IRCDMessageUID final
size_t offset = params[8][0] == '+' ? 0 : 1;
auto ts = IRCD->ExtractTimestamp(params[1]);
Anope::string modes = params[8+offset];
for (unsigned i = 9+offset; i < params.size() - 1; ++i)
modes += " " + params[i];
NickAlias *na = NULL;
if (SASL::sasl)
for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();)
@@ -2425,7 +2407,7 @@ struct IRCDMessageUID final
++it;
}
User *u = User::OnIntroduce(params[2], params[5+offset], params[3], params[4], params[6+offset], source.GetServer(), params[params.size() - 1], ts, modes, params[0], na ? *na->nc : NULL);
auto *u = User::OnIntroduce(params[2], params[5+offset], params[3], params[4], params[6+offset], source.GetServer(), params[params.size() - 1], ts, params[8 + offset], params[0], na ? *na->nc : NULL, { params.begin() + 9 + offset, params.end() - 1 });
if (u)
u->signon = IRCD->ExtractTimestamp(params[7+offset]);
}
+10 -13
View File
@@ -224,7 +224,7 @@ struct IRCDMessageChaninfo final
bool created;
Channel *c = Channel::FindOrCreate(params[0], created);
Anope::string modes = params[1];
std::vector<Anope::string> modeparams;
if (params.size() == 3)
{
@@ -237,17 +237,17 @@ struct IRCDMessageChaninfo final
switch(params[1][i])
{
case 'k':
modes += " " + params[2];
modeparams.push_back(params[2]);
continue;
case 'l':
modes += " " + params[3];
modeparams.push_back(params[3]);
continue;
}
}
c->ChangeTopicInternal(NULL, source.GetName(), params[4], Anope::CurTime);
}
c->SetModesInternal(source, modes);
c->SetModesInternal(source, params[1], modeparams);
}
};
@@ -267,11 +267,13 @@ struct IRCDMessageJoin final
User *user = source.GetUser();
size_t pos = params[0].find('\7');
Anope::string channel, modes;
std::vector<Anope::string> modeparams;
if (pos != Anope::string::npos)
{
channel = params[0].substr(0, pos);
modes = '+' + params[0].substr(pos+1, params[0].length()) + " " + user->nick;
modes = '+' + params[0].substr(pos+1, params[0].length());
modeparams.push_back(user->nick);
}
else
{
@@ -287,7 +289,7 @@ struct IRCDMessageJoin final
{
Channel *c = Channel::Find(channel);
if (c)
c->SetModesInternal(source, modes);
c->SetModesInternal(source, modes, modeparams);
}
}
};
@@ -367,17 +369,12 @@ struct IRCDMessageMode final
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override
{
Anope::string modes = params[1];
for (size_t i = 2; i < params.size(); ++i)
modes += " " + params[i];
if (IRCD->IsChannelValid(params[0]))
{
Channel *c = Channel::Find(params[0]);
if (c)
c->SetModesInternal(source, modes);
c->SetModesInternal(source, params[1], { params.begin() + 2, params.end() });
}
else
{
@@ -485,7 +482,7 @@ struct IRCDMessageNJoin final
users.push_back(sju);
}
Message::Join::SJoin(source, params[0], 0, "", users);
Message::Join::SJoin(source, params[0], 0, "", {}, users);
}
};
+1 -1
View File
@@ -33,7 +33,7 @@ class RatboxProto final
}
public:
RatboxProto(Module *creator) : IRCDProto(creator, "Ratbox 3.0+")
RatboxProto(Module *creator) : IRCDProto(creator, "ircd-ratbox 3+")
{
DefaultPseudoclientModes = "+oiS";
CanSNLine = true;
+123 -127
View File
@@ -14,7 +14,25 @@
#include "modules/sasl.h"
typedef Anope::map<Anope::string> ModData;
static Anope::string UplinkSID;
namespace
{
Anope::string UplinkSID;
bool IsExtBan(const Anope::string &str, Anope::string &name, Anope::string &value)
{
if (str[0] != '~')
return false;
auto endpos = str.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 1);
if (endpos == Anope::string::npos || str[endpos] != ':' || endpos+1 == str.length())
return false;
name = str.substr(1, endpos - 1);
value = str.substr(endpos + 1);
return true;
}
}
class UnrealIRCdProto final
: public IRCDProto
@@ -23,7 +41,10 @@ public:
PrimitiveExtensibleItem<ModData> ClientModData;
PrimitiveExtensibleItem<ModData> ChannelModData;
UnrealIRCdProto(Module *creator) : IRCDProto(creator, "UnrealIRCd 4+"), ClientModData(creator, "ClientModData"), ChannelModData(creator, "ChannelModData")
UnrealIRCdProto(Module *creator)
: IRCDProto(creator, "UnrealIRCd 6+")
, ClientModData(creator, "ClientModData")
, ChannelModData(creator, "ChannelModData")
{
DefaultPseudoclientModes = "+BioqS";
CanSVSNick = true;
@@ -216,21 +237,16 @@ private:
void SendConnect() override
{
/*
NICKv2 = Nick Version 2
VHP = Sends hidden host
UMODE2 = sends UMODE2 on user modes
NICKIP = Sends IP on NICK
SJ3 = Supports SJOIN
NOQUIT = No Quit
TKLEXT = Extended TKL we don't use it but best to have it
MLOCK = Supports the MLOCK server command
VL = Version Info
SID = SID/UID mode
*/
Uplink::Send("PASS", Config->Uplinks[Anope::CurrentUplink].password);
Uplink::Send("PROTOCTL", "NICKv2", "VHP", "UMODE2", "NICKIP", "SJOIN", "SJOIN2", "SJ3", "NOQUIT", "TKLEXT", "MLOCK", "SID", "MTAGS", "BIGLINES");
// BIGLINES: enable sending lines up to 16384 characters in length.
// EAUTH: communicates information about the local server.
// MLOCK: enable receiving the MLOCK message when a mode lock changes.
// MTAGS: enable receiving IRCv3 message tags.
// NEXTBANS: enables receiving named extended bans.
// SID: communicates the unique identifier of the local server.
// VHP: enable receiving the vhost in UID.
Uplink::Send("PROTOCTL", "BIGLINES", "MLOCK", "MTAGS", "NEXTBANS", "VHP");
Uplink::Send("PROTOCTL", "EAUTH=" + Me->GetName() + ",,,Anope-" + Anope::VersionShort());
Uplink::Send("PROTOCTL", "SID=" + Me->GetSID());
@@ -348,16 +364,14 @@ private:
bool IsExtbanValid(const Anope::string &mask) override
{
return mask.length() >= 4 && mask[0] == '~' && mask[2] == ':';
Anope::string name, value;
return IsExtBan(mask, name, value);
}
void SendLogin(User *u, NickAlias *na) override
{
/* 3.2.10.4+ treats users logged in with accounts as fully registered, even if -r, so we can not set this here. Just use the timestamp. */
if (Servers::Capab.count("ESVID") > 0 && !na->nc->HasExt("UNCONFIRMED"))
if (!na->nc->HasExt("UNCONFIRMED"))
IRCD->SendMode(Config->GetClient("NickServ"), u, "+d", na->nc->display);
else
IRCD->SendMode(Config->GetClient("NickServ"), u, "+d", u->signon);
}
void SendLogout(User *u) override
@@ -448,54 +462,65 @@ private:
bool IsTagValid(const Anope::string &tname, const Anope::string &tvalue) override
{
if (Servers::Capab.count("MTAGS"))
return true;
return false;
return !!Servers::Capab.count("MTAGS");
}
};
class UnrealExtBan
: public ChannelModeVirtual<ChannelModeList>
namespace UnrealExtBan
{
char ext;
public:
UnrealExtBan(const Anope::string &mname, const Anope::string &basename, char extban) : ChannelModeVirtual<ChannelModeList>(mname, basename)
, ext(extban)
class Base
: public ChannelModeVirtual<ChannelModeList>
{
}
private:
char xbchar;
Anope::string xbname;
ChannelMode *Wrap(Anope::string &param) override
{
param = "~" + Anope::string(ext) + ":" + param;
return ChannelModeVirtual<ChannelModeList>::Wrap(param);
}
public:
Base(const Anope::string &mname, const Anope::string& uname, char uchar)
: ChannelModeVirtual<ChannelModeList>(mname, "BAN")
, xbchar(uchar)
, xbname(uname)
{
}
ChannelMode *Unwrap(ChannelMode *cm, Anope::string &param) override
{
if (cm->type != MODE_LIST || param.length() < 4 || param[0] != '~' || param[1] != ext || param[2] != ':')
return cm;
ChannelMode *Wrap(Anope::string &param) override
{
auto prefix = Servers::Capab.count("NEXTBANS") ? xbname : Anope::string(xbchar);
param = Anope::printf("~%s:%s", prefix.c_str(), param.c_str());
return ChannelModeVirtual<ChannelModeList>::Wrap(param);
}
param = param.substr(3);
return this;
}
};
ChannelMode *Unwrap(ChannelMode *cm, Anope::string &param) override
{
// The mask must be in the format ~<letter>:<value> or ~<name>:<value>.
if (cm->type != MODE_LIST)
return cm;
Anope::string name, value;
if (!IsExtBan(param, name, value))
return cm;
if (name.length() == 1 ? name[0] != xbchar : name != xbname)
return cm;
param = value;
return this;
}
};
namespace UnrealExtban
{
class ChannelMatcher final
: public UnrealExtBan
: public Base
{
public:
ChannelMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
ChannelMatcher()
: Base("CHANNELBAN", "channel", 'c')
{
}
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string channel = mask.substr(3);
auto channel = e->GetMask();
ChannelMode *cm = NULL;
if (channel[0] != '#')
{
@@ -520,137 +545,113 @@ namespace UnrealExtban
};
class EntryMatcher final
: public UnrealExtBan
: public Base
{
public:
EntryMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
EntryMatcher(const Anope::string &mname, const Anope::string &uname, char uchar)
: Base(mname, uname, uchar)
{
}
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(3);
return Entry(this->name, real_mask).Matches(u);
return Entry(this->base, e->GetMask()).Matches(u);
}
};
class RealnameMatcher final
: public UnrealExtBan
: public Base
{
public:
RealnameMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
RealnameMatcher()
: Base("REALNAMEBAN", "realname", 'r')
{
}
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(3);
return Anope::Match(u->realname, real_mask);
}
};
class RegisteredMatcher final
: public UnrealExtBan
{
public:
RegisteredMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
{
}
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
return u->HasMode("REGISTERED") && mask.equals_ci(u->nick);
return Anope::Match(u->realname, e->GetMask());
}
};
class AccountMatcher final
: public UnrealExtBan
: public Base
{
public:
AccountMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
AccountMatcher()
: Base("ACCOUNTBAN", "account", 'a')
{
}
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(3);
if (real_mask == "0" && !u->Account()) /* ~a:0 is special and matches all unauthenticated users */
if (e->GetMask() == "0" && !u->Account()) /* ~a:0 is special and matches all unauthenticated users */
return true;
return u->Account() && Anope::Match(u->Account()->display, real_mask);
return u->IsIdentified() && Anope::Match(u->Account()->display, e->GetMask());
}
};
class FingerprintMatcher final
: public UnrealExtBan
: public Base
{
public:
FingerprintMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
FingerprintMatcher()
: Base("SSLBAN", "certfp", 'S')
{
}
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(3);
return !u->fingerprint.empty() && Anope::Match(u->fingerprint, real_mask);
return !u->fingerprint.empty() && Anope::Match(u->fingerprint, e->GetMask());
}
};
class OperclassMatcher final
: public UnrealExtBan
: public Base
{
public:
OperclassMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
OperclassMatcher()
: Base("OPERCLASSBAN", "operclass", 'O')
{
}
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(3);
ModData *moddata = u->GetExt<ModData>("ClientModData");
return moddata != NULL && moddata->find("operclass") != moddata->end() && Anope::Match((*moddata)["operclass"], real_mask);
return moddata != NULL && moddata->find("operclass") != moddata->end() && Anope::Match((*moddata)["operclass"], e->GetMask());
}
};
class TimedBanMatcher final
: public UnrealExtBan
: public Base
{
public:
TimedBanMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
TimedBanMatcher()
: Base("TIMEDBAN", "time", 't')
{
}
bool Matches(User *u, const Entry *e) override
{
/* strip down the time (~t:1234:) and call other matchers */
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(3);
auto real_mask = e->GetMask();
real_mask = real_mask.substr(real_mask.find(":") + 1);
return Entry("BAN", real_mask).Matches(u);
}
};
class CountryMatcher final
: public UnrealExtBan
: public Base
{
public:
CountryMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
CountryMatcher()
: Base("COUNTRYBAN", "country", 'C')
{
}
bool Matches(User *u, const Entry *e) override
{
const Anope::string &mask = e->GetMask();
Anope::string real_mask = mask.substr(3);
ModData *moddata = u->GetExt<ModData>("ClientModData");
if (moddata == NULL || moddata->find("geoip") == moddata->end())
return false;
@@ -660,7 +661,7 @@ namespace UnrealExtban
while (sep.GetToken(tokenbuf))
{
if (tokenbuf.rfind("cc=", 0) == 0)
return (tokenbuf.substr(3, 2) == real_mask);
return (tokenbuf.substr(3, 2) == e->GetMask());
}
return false;
}
@@ -846,17 +847,16 @@ struct IRCDMessageCapab final
case 'b':
ModeManager::AddChannelMode(new ChannelModeList("BAN", 'b'));
ModeManager::AddChannelMode(new UnrealExtban::ChannelMatcher("CHANNELBAN", "BAN", 'c'));
ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("JOINBAN", "BAN", 'j'));
ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("NONICKBAN", "BAN", 'n'));
ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("QUIET", "BAN", 'q'));
ModeManager::AddChannelMode(new UnrealExtban::RealnameMatcher("REALNAMEBAN", "BAN", 'r'));
ModeManager::AddChannelMode(new UnrealExtban::RegisteredMatcher("REGISTEREDBAN", "BAN", 'R'));
ModeManager::AddChannelMode(new UnrealExtban::AccountMatcher("ACCOUNTBAN", "BAN", 'a'));
ModeManager::AddChannelMode(new UnrealExtban::FingerprintMatcher("SSLBAN", "BAN", 'S'));
ModeManager::AddChannelMode(new UnrealExtban::TimedBanMatcher("TIMEDBAN", "BAN", 't'));
ModeManager::AddChannelMode(new UnrealExtban::OperclassMatcher("OPERCLASSBAN", "BAN", 'O'));
ModeManager::AddChannelMode(new UnrealExtban::CountryMatcher("COUNTRYBAN", "BAN", 'C'));
ModeManager::AddChannelMode(new UnrealExtBan::ChannelMatcher());
ModeManager::AddChannelMode(new UnrealExtBan::EntryMatcher("JOINBAN", "join", 'j'));
ModeManager::AddChannelMode(new UnrealExtBan::EntryMatcher("NONICKBAN", "nickchange", 'n'));
ModeManager::AddChannelMode(new UnrealExtBan::EntryMatcher("QUIET", "quiet", 'q'));
ModeManager::AddChannelMode(new UnrealExtBan::RealnameMatcher());
ModeManager::AddChannelMode(new UnrealExtBan::AccountMatcher());
ModeManager::AddChannelMode(new UnrealExtBan::FingerprintMatcher());
ModeManager::AddChannelMode(new UnrealExtBan::TimedBanMatcher());
ModeManager::AddChannelMode(new UnrealExtBan::OperclassMatcher());
ModeManager::AddChannelMode(new UnrealExtBan::CountryMatcher());
continue;
case 'e':
ModeManager::AddChannelMode(new ChannelModeList("EXCEPT", 'e'));
@@ -1155,10 +1155,7 @@ struct IRCDMessageMode final
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override
{
auto final_is_ts = server_ts && source.GetServer() != NULL;
Anope::string modes = params[1];
for (unsigned i = 2; i < params.size() - (final_is_ts ? 1 : 0); ++i)
modes += " " + params[i];
auto last_param = params.end() - (params.size() > 3 && final_is_ts ? 1 : 0);
if (IRCD->IsChannelValid(params[0]))
{
@@ -1166,7 +1163,7 @@ struct IRCDMessageMode final
auto ts = final_is_ts ? IRCD->ExtractTimestamp(params.back()) : 0;
if (c)
c->SetModesInternal(source, modes, ts);
c->SetModesInternal(source, params[1], { params.begin() + 2, last_param }, ts);
}
else
{
@@ -1428,11 +1425,12 @@ struct IRCDMessageSJoin final
void Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags) override
{
Anope::string modes;
std::vector<Anope::string> modeparams;
if (params.size() >= 4)
for (unsigned i = 2; i < params.size() - 1; ++i)
modes += " " + params[i];
if (!modes.empty())
modes.erase(modes.begin());
{
modes = params[2];
modeparams = { params.begin() + 3, params.end() };
}
std::list<Anope::string> bans, excepts, invites;
std::list<Message::Join::SJoinUser> users;
@@ -1482,7 +1480,7 @@ struct IRCDMessageSJoin final
}
auto ts = IRCD->ExtractTimestamp(params[0]);
Message::Join::SJoin(source, params[1], ts, modes, users);
Message::Join::SJoin(source, params[1], ts, modes, modeparams, users);
if (!bans.empty() || !excepts.empty() || !invites.empty())
{
@@ -1753,8 +1751,6 @@ public:
void OnUserNickChange(User *u, const Anope::string &) override
{
u->RemoveModeInternal(Me, ModeManager::FindUserModeByName("REGISTERED"));
if (Servers::Capab.count("ESVID") == 0)
IRCD->SendLogout(u);
}
void OnChannelSync(Channel *c) override
+1 -1
View File
@@ -48,7 +48,7 @@ public:
{
SQLOperResultDeleter d(this);
if (!user || !user->Account())
if (!user || !user->IsIdentified())
return;
if (r.Rows() == 0)
+1 -1
View File
@@ -226,7 +226,7 @@ private:
request.reply("ip", u->ip.addr());
request.reply("timestamp", Anope::ToString(u->timestamp));
request.reply("signon", Anope::ToString(u->signon));
if (u->Account())
if (u->IsIdentified())
{
request.reply("account", iface->Sanitize(u->Account()->display));
if (u->Account()->o)
+22 -4
View File
@@ -20,7 +20,11 @@
Serialize::Checker<botinfo_map> BotListByNick("BotInfo"), BotListByUID("BotInfo");
BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const Anope::string &nhost, const Anope::string &nreal, const Anope::string &bmodes) : User(nnick, nuser, nhost, "", "", Me, nreal, Anope::CurTime, "", IRCD ? IRCD->UID_Retrieve() : "", NULL), Serializable("BotInfo"), channels("ChannelInfo"), botmodes(bmodes)
BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const Anope::string &nhost, const Anope::string &nreal, const Anope::string &bmodes)
: User(nnick, nuser, nhost, "", "", Me, nreal, Anope::CurTime, "", {}, IRCD ? IRCD->UID_Retrieve() : "", NULL)
, Serializable("BotInfo")
, channels("ChannelInfo")
, botmodes(bmodes)
{
this->lastmsg = this->created = Anope::CurTime;
this->introduced = false;
@@ -35,9 +39,16 @@ BotInfo::BotInfo(const Anope::string &nnick, const Anope::string &nuser, const A
// If we're synchronised with the uplink already, send the bot.
if (Me && Me->IsSynced())
{
Anope::string tmodes = !this->botmodes.empty() ? ("+" + this->botmodes) : IRCD->DefaultPseudoclientModes;
if (!tmodes.empty())
this->SetModesInternal(this, tmodes);
spacesepstream modesep(this->botmodes.empty() ? IRCD->DefaultPseudoclientModes : "+" + this->botmodes);
Anope::string modechars;
modesep.GetToken(modechars);
std::vector<Anope::string> modeparams;
modesep.GetTokens(modeparams);
if (!modechars.empty())
this->SetModesInternal(this, modechars, modeparams);
XLine x(this->nick, "Reserved for services");
IRCD->SendSQLine(NULL, &x);
@@ -254,6 +265,13 @@ CommandInfo *BotInfo::GetCommand(const Anope::string &cname)
return NULL;
}
Anope::string BotInfo::GetQueryCommand() const
{
if (Config->ServiceAlias && !this->alias.empty())
return Anope::printf("/%s", this->alias.c_str());
return Anope::printf("/msg %s", this->nick.c_str());
}
BotInfo *BotInfo::Find(const Anope::string &nick, bool nick_only)
{
if (!nick_only && IRCD != NULL && IRCD->RequiresID)
+13 -15
View File
@@ -611,13 +611,13 @@ void Channel::SetModes(BotInfo *bi, bool enforce_mlock, const Anope::string &cmo
}
}
void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode, time_t ts, bool enforce_mlock)
void Channel::SetModesInternal(MessageSource &source, const Anope::string &modes, const std::vector<Anope::string> &params, time_t ts, bool enforce_mlock)
{
if (!ts)
;
else if (ts > this->creation_time)
{
Log(LOG_DEBUG) << "Dropping mode " << mode << " on " << this->name << ", " << ts << " > " << this->creation_time;
Log(LOG_DEBUG) << "Dropping mode " << modes << " on " << this->name << ", " << ts << " > " << this->creation_time;
return;
}
else if (ts < this->creation_time)
@@ -631,20 +631,18 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode,
/* Removing channel modes *may* delete this channel */
Reference<Channel> this_reference(this);
spacesepstream sep_modes(mode);
Anope::string m;
sep_modes.GetToken(m);
Anope::string modestring;
Anope::string paramstring;
int add = -1;
bool changed = false;
for (unsigned int i = 0, end = m.length(); i < end && this_reference; ++i)
auto paramit = params.begin();
for (const auto mchar : modes)
{
ChannelMode *cm;
if (!this_reference)
break;
switch (m[i])
ChannelMode *cm;
switch (mchar)
{
case '+':
modestring += '+';
@@ -657,10 +655,10 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode,
default:
if (add == -1)
continue;
cm = ModeManager::FindChannelModeByChar(m[i]);
cm = ModeManager::FindChannelModeByChar(mchar);
if (!cm)
{
Log(LOG_DEBUG) << "Channel::SetModeInternal: Unknown mode char " << m[i];
Log(LOG_DEBUG) << "Channel::SetModeInternal: Unknown mode char " << mchar;
continue;
}
modestring += cm->mchar;
@@ -686,9 +684,9 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode,
continue;
}
}
Anope::string token;
if (sep_modes.GetToken(token))
if (paramit != params.end())
{
auto token = *paramit++;
User *u = NULL;
if (cm->type == MODE_STATUS && (u = User::Find(token)))
paramstring += " " + u->nick;
@@ -703,7 +701,7 @@ void Channel::SetModesInternal(MessageSource &source, const Anope::string &mode,
this->RemoveModeInternal(source, cm, token, enforce_mlock);
}
else
Log() << "warning: Channel::SetModesInternal() received more modes requiring params than params, modes: " << mode;
Log() << "warning: Channel::SetModesInternal() received more modes requiring params than params, modes: " << modes;
}
if (!this_reference)

Some files were not shown because too many files have changed in this diff Show More