1
0
mirror of https://github.com/anope/anope.git synced 2026-06-18 03:54:46 +02:00

Compare commits

...

18 Commits

Author SHA1 Message Date
Sadie Powell 206192abdc Release 2.1.17. 2025-08-01 12:21:00 +01:00
Sadie Powell 32d3ddc0e4 Fix the grammar of two messages. 2025-07-30 15:30:44 +01:00
Sadie Powell 4410e5ccce Update the change logs. 2025-07-27 19:23:02 +01:00
Sadie Powell d5f2232140 Fix importing some older databases. 2025-07-27 15:42:32 +01:00
Sadie Powell 6d754b7d73 Add the intended target of the mode to CanSet. 2025-07-25 21:07:26 +01:00
Sadie Powell 4d2870fa45 Make it more clear that db_flatfile is deprecated. 2025-07-25 13:38:13 +01:00
Sadie Powell 5948c2ea53 Simplify the Windows module copying logic.
As far as I can tell from reading the Windows documentation there
is no reason to overcomplicate this so much.
2025-07-25 13:21:15 +01:00
Sadie Powell ace7d99797 Tweak the default ns_set_misc examples slightly.
- Discord is proprietary software so we shouldn't be encouraging
  its use. ;-)

- Time zone is going to be replaced by a future feature that allows
  users to get timestamps in their local time so I'm removing it
  now to prevent future conflict.

- Location is a good example of how this should be used for extra
  fields.
2025-07-25 12:53:47 +01:00
Sadie Powell 52595b90fa Rewrite nickserv/resend with some functionality improvements.
- Allow server operators to resend a confirmation email. Closes #518.
- Allow use of the command whilst unauthenticated.
2025-07-25 12:28:14 +01:00
Sadie Powell b39f002d1b Remove some unused files. 2025-07-21 19:14:34 +01:00
Sadie Powell 5df95d9f86 Remove a variant message which is only used in one place. 2025-07-12 16:33:14 +01:00
Sadie Powell a56d9a4096 Only show the last quit message if the user is not online. 2025-07-12 15:28:57 +01:00
Sadie Powell ce7bb15c18 Use IsIdentValid for validating usernames in hs_request. 2025-07-12 14:41:09 +01:00
Sadie Powell 6873630f2e Improve the "please identify" messages. 2025-07-08 16:24:16 +01:00
Sadie Powell 44a4d62654 Show the last real mask to services operators with nickserv/list. 2025-07-07 11:51:10 +01:00
Sadie Powell 97389cd105 Rename some fields to be more accurately named. 2025-07-07 11:51:10 +01:00
Sadie Powell 80c0adf7c8 Make a message consistent with others. 2025-07-02 14:08:04 +01:00
Sadie Powell 6a539277b9 Bump for 2.1.17-git. 2025-07-01 10:58:05 +01:00
39 changed files with 242 additions and 628 deletions
BIN
View File
Binary file not shown.
+5 -3
View File
@@ -747,6 +747,7 @@ log
* nickserv/drop/display - Allows dropping display nicks when preservedisplay is enabled
* nickserv/drop/override - Allows dropping nicks without using a confirmation code
* nickserv/recover - Can recover other users nicks
* nickserv/resend - Can resend confirmation codes via email
* operserv/config - Can modify services's configuration
* operserv/oper/modify - Can add and remove operators with at most the same privileges
* protected - Can not be kicked from channels by services
@@ -811,7 +812,7 @@ opertype
inherits = "Helper, Another Helper"
/* What commands (see above) this opertype may use */
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
commands = "chanserv/list chanserv/suspend chanserv/topic memoserv/staff nickserv/list nickserv/resend nickserv/suspend operserv/mode operserv/chankill operserv/akill operserv/session operserv/modinfo operserv/sqline operserv/oper operserv/kick operserv/ignore operserv/snline"
/* What privs (see above) this opertype has */
privs = "chanserv/auspex chanserv/no-register-limit memoserv/* nickserv/auspex nickserv/confirm/*"
@@ -1101,14 +1102,15 @@ mail
}
/*
* db_flatfile
* [DEPRECATED] db_flatfile
*
* Stores your database in a custom flatfile format.
*
* This was the recommended database module in 2.0 but it is now recommended
* that you use db_json instead. You can migrate your db_flatfile database to
* db_json by loading db_flatfile BEFORE db_json, sending SIGUSR1 to force a
* database write, and then unloading db_flatfile.
* database write, and then unloading db_flatfile. This module will become
* import-only in a future release.
*/
#module
{
+2 -4
View File
@@ -696,12 +696,10 @@ command { service = "NickServ"; name = "SASET LANGUAGE"; command = "nickserv/sas
module { name = "ns_set_misc" }
command { service = "NickServ"; name = "SET URL"; command = "nickserv/set/misc"; misc_description = _("Associate a URL with your account"); }
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 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"; }
#command { service = "NickServ"; name = "SET LOCATION"; command = "nickserv/set/misc"; misc_description = _("Associate a location with your account"); }
#command { service = "NickServ"; name = "SASET LOCATION"; command = "nickserv/saset/misc"; misc_description = _("Associate a location with this account"); permission = "nickserv/saset/location"; group = "nickserv/admin"; }
/*
* ns_set_protect
+8
View File
@@ -1,3 +1,11 @@
Anope Version 2.1.17
--------------------
Allowed opers to resend passwords for users in nickserv/resend.
Fixed HostServ using a different valid username character set to the protocol module.
Fixed losing the channel and nickname registration time when upgrading from an earlier 2.1 release.
Improved the messages sent when a user is forced off a protected nickname.
Simplified copying modules to the runtime directory on Windows.
Anope Version 2.1.16
--------------------
Added support for on-IRC code confirmation.
+4
View File
@@ -1,3 +1,7 @@
Anope Version 2.1.17
--------------------
Added the nickserv/resend oper privilege.
Anope Version 2.1.16
--------------------
Added fantasy:require_privilege (defaults to yes).
+4 -4
View File
@@ -49,10 +49,10 @@ public:
Anope::string nick;
Anope::string last_quit;
Anope::string last_realname;
/* Last usermask this nick was seen on, eg user@host */
Anope::string last_usermask;
/* Last uncloaked usermask, requires nickserv/auspex to see */
Anope::string last_realhost;
/* Last cloaked user@host this nick was seen using. */
Anope::string last_userhost;
/* Last real user@host this nick was seen using. */
Anope::string last_userhost_real;
time_t registered = Anope::CurTime;
time_t last_seen = Anope::CurTime;
-5
View File
@@ -114,7 +114,6 @@ namespace Language
"cannot contain the space or tab characters.")
#define PASSWORD_TOO_SHORT _("Your password is too short. It must be longer than %u characters.")
#define PASSWORD_TOO_LONG _("Your password is too long. It must be shorter than %u characters.")
#define NICK_NOT_REGISTERED _("Your nick isn't registered.")
#define NICK_X_NOT_REGISTERED _("Nick \002%s\002 isn't registered.")
#define NICK_X_NOT_IN_USE _("Nick \002%s\002 isn't currently in use.")
#define NICK_X_NOT_ON_CHAN _("\002%s\002 is not currently on channel %s.")
@@ -127,10 +126,6 @@ namespace Language
#define UNKNOWN _("<unknown>")
#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 " \
"nick, type \002%s\032\037password\037\002. Otherwise, " \
"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.")
#define NICK_ALREADY_REGISTERED _("Nickname \002%s\002 is already registered!")
#define NICK_SET_DISPLAY_CHANGED _("The new display is now \002%s\002.")
+15 -10
View File
@@ -70,11 +70,6 @@ public:
*/
Mode(const Anope::string &mname, ModeClass mclass, char mc, ModeType type);
virtual ~Mode() = default;
/** Can a user set this mode, used for mlock
* @param u The user
*/
virtual bool CanSet(User *u) const;
};
/** This class is a user mode, all user modes use this/inherit from this
@@ -88,6 +83,12 @@ public:
* @param mc The mode char
*/
UserMode(const Anope::string &name, char mc);
/** Can a user set this mode, used for mlock
* @param source The user who is setting the mode.
* @param target The user the mode is being set on.
*/
virtual bool CanSet(User *source, User *target) const { return true; }
};
class CoreExport UserModeParam
@@ -122,7 +123,11 @@ public:
*/
ChannelMode(const Anope::string &name, char mc);
bool CanSet(User *u) const override;
/** Can a user set this mode, used for mlock
* @param u The user who is setting the mode.
* @param c The channel the mode is being set on.
*/
virtual bool CanSet(User *u, Channel *c) const;
virtual void Check() { }
@@ -270,7 +275,7 @@ class CoreExport UserModeOperOnly
public:
UserModeOperOnly(const Anope::string &mname, char um) : UserMode(mname, um) { }
bool CanSet(User *u) const override;
bool CanSet(User *source, User *target) const override;
};
class CoreExport UserModeNoone
@@ -279,7 +284,7 @@ class CoreExport UserModeNoone
public:
UserModeNoone(const Anope::string &mname, char um) : UserMode(mname, um) { }
bool CanSet(User *u) const override;
bool CanSet(User *source, User *target) const override;
};
/** Channel mode +k (key)
@@ -302,7 +307,7 @@ public:
ChannelModeOperOnly(const Anope::string &mname, char mc) : ChannelMode(mname, mc) { }
/* Opers only */
bool CanSet(User *u) const override;
bool CanSet(User *u, Channel *c) const override;
};
/** This class is used for channel modes only servers may set
@@ -313,7 +318,7 @@ class CoreExport ChannelModeNoone
public:
ChannelModeNoone(const Anope::string &mname, char mc) : ChannelMode(mname, mc) { }
bool CanSet(User *u) const override;
bool CanSet(User *u, Channel *c) const override;
};
/** This is the mode manager
+2 -1
View File
@@ -1046,9 +1046,10 @@ public:
/** Called to determine if a channel mode can be set by a user
* @param u The user
* @param c The channel
* @param cm The mode
*/
virtual EventReturn OnCanSet(User *u, const ChannelMode *cm) ATTR_NOT_NULL(2, 3) { throw NotImplementedException(); }
virtual EventReturn OnCanSet(User *u, Channel *c, const ChannelMode *cm) ATTR_NOT_NULL(2, 3) { throw NotImplementedException(); }
virtual EventReturn OnCheckDelete(Channel *c) ATTR_NOT_NULL(2) { throw NotImplementedException(); }
+1 -1
View File
@@ -253,7 +253,7 @@ public:
*/
bool HasPriv(const Anope::string &privstr);
/** Update the last usermask stored for a user. */
/** Update the last mask stored for a user. */
void UpdateHost();
/** Update the away state for a user. */
+31 -33
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Anope\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-06-25 15:33+0100\n"
"PO-Revision-Date: 2025-06-25 15:33+0100\n"
"POT-Creation-Date: 2025-07-30 15:30+0100\n"
"PO-Revision-Date: 2025-07-30 15:30+0100\n"
"Last-Translator: Sadie Powell <sadie@witchery.services>\n"
"Language-Team: English\n"
"Language: en_US\n"
@@ -597,7 +597,7 @@ msgstr ""
msgid "nickname [+expiry] [reason]"
msgstr ""
msgid "nickname {EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}"
msgid "nickname {EMAIL | STATUS | MASK | QUIT} {ON | OFF}"
msgstr ""
msgid "nickname {ON | delay | OFF}"
@@ -1341,6 +1341,9 @@ msgstr ""
msgid "Additionally, Services Operators with the nickserv/drop/override permission can replace code with OVERRIDE to drop without a confirmation code."
msgstr ""
msgid "Additionally, Services Operators with the nickserv/resend permission can specify a nickname to resend a confirmation email for another account."
msgstr ""
#, c-format
msgid "Additionally, if fantasy is enabled fantasy commands can be executed by prefixing the command name with one of the following characters: %s"
msgstr ""
@@ -1520,7 +1523,7 @@ msgstr ""
msgid ""
"Allows Services Operators to manipulate the AKILL list. If a user matching an AKILL mask attempts to connect, services will issue a KILL for that user and, on supported server types, will instruct all servers to add a ban for the mask which the user matched.\n"
"\n"
"%sADD adds the given mask to the AKILL list for the given reason, which must be given. Mask should be in the format of nick!user@host#realname, though all that is required is user@host. If a real name is specified, the reason must be prepended with a :. expiry is specified as an integer followed by one of d (days), h (hours), or m (minutes). Combinations (such as 1h30m) are not permitted. If a unit specifier is not included, the default is days (so +30 by itself means 30 days). To add an AKILL which does not expire, use +0. If the usermask to be added starts with a +, an expiry time must be given, even if it is the same as the default. The current AKILL default expiry time can be found with the STATSAKILL command."
"%sADD adds the given mask to the AKILL list for the given reason, which must be given. Mask should be in the format of nick!user@host#realname, though all that is required is user@host. If a real name is specified, the reason must be prepended with a :. expiry is specified as an integer followed by one of d (days), h (hours), or m (minutes). Combinations (such as 1h30m) are not permitted. If a unit specifier is not included, the default is days (so +30 by itself means 30 days). To add an AKILL which does not expire, use +0. If the mask to be added starts with a +, an expiry time must be given, even if it is the same as the default. The current AKILL default expiry time can be found with the STATSAKILL command."
msgstr ""
msgid ""
@@ -1631,11 +1634,11 @@ msgid "Allows you to kill a user from the network. Parameters are the same as fo
msgstr ""
#, c-format
msgid "Allows you to prevent certain pieces of information from being displayed when someone does a %sINFO on the nick. You can hide the email address (EMAIL), last seen user@host mask (USERMASK), the services access status (STATUS) and last quit message (QUIT). The second parameter specifies whether the information should be displayed (OFF) or hidden (ON)."
msgid "Allows you to prevent certain pieces of information from being displayed when someone does a %sINFO on the nick. You can hide the email address (EMAIL), last seen user@host mask (MASK), the services access status (STATUS) and last quit message (QUIT). The second parameter specifies whether the information should be displayed (OFF) or hidden (ON)."
msgstr ""
#, c-format
msgid "Allows you to prevent certain pieces of information from being displayed when someone does a %sINFO on your nick. You can hide your email address(EMAIL), last seen user@host mask (USERMASK), your services access status (STATUS) and last quit message (QUIT). The second parameter specifies whether the information should be displayed (OFF) or hidden (ON)."
msgid "Allows you to prevent certain pieces of information from being displayed when someone does a %sINFO on your nick. You can hide your email address(EMAIL), last seen user@host mask (MASK), your services access status (STATUS) and last quit message (QUIT). The second parameter specifies whether the information should be displayed (OFF) or hidden (ON)."
msgstr ""
#, c-format
@@ -3012,10 +3015,6 @@ msgstr ""
msgid "Identify yourself with your password"
msgstr ""
#, c-format
msgid "If you do not change within %s, I will change your nick."
msgstr ""
msgid "Ignore list has been cleared."
msgstr ""
@@ -3133,6 +3132,9 @@ msgstr ""
msgid "Language for %s changed to %s."
msgstr ""
msgid "Last mask"
msgstr ""
#, c-format
msgid "Last memo to %s has been cancelled."
msgstr ""
@@ -3143,7 +3145,7 @@ msgstr ""
msgid "Last seen"
msgstr ""
msgid "Last seen address"
msgid "Last seen mask"
msgstr ""
msgid "Last topic"
@@ -3152,9 +3154,6 @@ msgstr ""
msgid "Last used"
msgstr ""
msgid "Last usermask"
msgstr ""
msgid "Level"
msgstr ""
@@ -3390,7 +3389,7 @@ msgstr ""
msgid ""
"Maintains the AutoKick list for a channel. If a user on the AutoKick list attempts to join the channel, %s will ban that user from the channel, then kick the user.\n"
"\n"
"The %sADD command adds the given nick or usermask to the AutoKick list. If a reason is given with the command, that reason will be used when the user is kicked; if not, the default reason is \"User has been banned from the channel\". When akicking a registered nick the %s account will be added to the akick list instead of the mask. All users within that nickgroup will then be akicked. \n"
"The %sADD command adds the given nick or mask to the AutoKick list. If a reason is given with the command, that reason will be used when the user is kicked; if not, the default reason is \"User has been banned from the channel\". When akicking a registered nick the %s account will be added to the akick list instead of the mask. All users within that nickgroup will then be akicked. \n"
"\n"
"The %sDEL command removes the given nick or mask from the AutoKick list. It does not, however, remove any bans placed by an AutoKick; those must be removed manually.\n"
"\n"
@@ -3677,6 +3676,10 @@ msgstr ""
msgid "Nick %s is already an operator."
msgstr ""
#, c-format
msgid "Nick %s is already confirmed."
msgstr ""
#, c-format
msgid "Nick %s is an illegal nickname and cannot be used."
msgstr ""
@@ -3782,7 +3785,7 @@ msgstr ""
msgid "No bot"
msgstr ""
msgid "No expire"
msgid "No expiry"
msgstr ""
#, c-format
@@ -5165,6 +5168,10 @@ msgstr ""
msgid "The Defcon level is now at: %d"
msgstr ""
#, c-format
msgid "The confirmation code for %s has been re-sent to %s."
msgstr ""
msgid "The defcon system can be used to implement a pre-defined set of restrictions to services useful during an attempted attack on the network."
msgstr ""
@@ -5453,7 +5460,7 @@ msgstr ""
msgid "This command unloads the module named modname."
msgstr ""
msgid "This command will resend you the registration confirmation email."
msgid "This command will resend a registration confirmation email."
msgstr ""
#, c-format
@@ -5468,14 +5475,11 @@ msgstr ""
msgid "This nickname has been recovered by %s. If you did not do this then %s may have your password, and you should change it."
msgstr ""
msgid "This nickname has been registered; you may not use it."
msgstr ""
msgid "This nickname is suspended."
msgstr ""
#, c-format
msgid "This nickname is registered and protected. If it is your nick, type %spassword. Otherwise, please choose a different nick."
msgid "This nickname is registered and has protection enabled. If it belongs to you, type %spassword to identify to your account."
msgstr ""
msgid "This option makes a channel unassignable. If a bot is already assigned to the channel, it is unassigned automatically when you enable it."
@@ -5638,11 +5642,11 @@ msgid "Unknown command %s. Did you mean %s?"
msgstr ""
#, c-format
msgid "Unknown command %s. Did you mean %s? Type \"%s\" for help."
msgid "Unknown command %s. Did you mean %s? Type %s for help."
msgstr ""
#, c-format
msgid "Unknown command %s. Type \"%s\" for help."
msgid "Unknown command %s. Type %s for help."
msgstr ""
#, c-format
@@ -6174,9 +6178,6 @@ msgstr ""
msgid "Your account %s has been successfully created."
msgstr ""
msgid "Your account is already confirmed."
msgstr ""
msgid "Your account is not confirmed. To confirm it, follow the instructions that were emailed to you."
msgstr ""
@@ -6188,10 +6189,6 @@ msgstr ""
msgid "Your account will expire, if not confirmed, in %s."
msgstr ""
#, c-format
msgid "Your confirmation code has been re-sent to %s."
msgstr ""
#, c-format
msgid "Your email address has been updated to %s"
msgstr ""
@@ -6239,9 +6236,6 @@ msgstr ""
msgid "Your nick is already registered."
msgstr ""
msgid "Your nick isn't registered."
msgstr ""
#, c-format
msgid "Your nickname is now being changed to %s"
msgstr ""
@@ -6250,6 +6244,10 @@ msgstr ""
msgid "Your nickname now belongs to the account %s."
msgstr ""
#, c-format
msgid "Your nickname will be changed in %s if you do not identify."
msgstr ""
msgid "Your oper block doesn't require logging in."
msgstr ""
+1 -1
View File
@@ -330,7 +330,7 @@ public:
ci->Extend<bool>(def.upper());
}
EventReturn OnCanSet(User *u, const ChannelMode *cm) override
EventReturn OnCanSet(User *u, Channel *c, const ChannelMode *cm) override
{
if (Config->GetModule(this).Get<const Anope::string>("nomlock").find(cm->mchar) != Anope::string::npos
|| Config->GetModule(this).Get<const Anope::string>("require").find(cm->mchar) != Anope::string::npos)
+3 -3
View File
@@ -141,7 +141,7 @@ class CommandCSAKick final
}
}
/* Match against the lastusermask of all nickalias's with equal
/* Match against the last mask of all nickalias's with equal
* or higher access. - Viper */
for (const auto &[_, na2] : *NickAliasList)
{
@@ -150,7 +150,7 @@ class CommandCSAKick final
AccessGroup nc_access = ci->AccessFor(na->nc), u_access = source.AccessFor(ci);
if (na->nc && (na->nc == ci->GetFounder() || nc_access >= u_access))
{
Anope::string buf = na->nick + "!" + na->last_usermask;
Anope::string buf = na->nick + "!" + na->last_userhost;
if (Anope::Match(buf, mask))
{
source.Reply(ACCESS_DENIED);
@@ -506,7 +506,7 @@ public:
"%s will ban that user from the channel, then kick "
"the user."
"\n\n"
"The \002%s\032ADD\002 command adds the given nick or usermask "
"The \002%s\032ADD\002 command adds the given nick or mask "
"to the AutoKick list. If a \037reason\037 is given with "
"the command, that reason will be used when the user is "
"kicked; if not, the default reason is \"User has been "
+5 -5
View File
@@ -288,7 +288,7 @@ class CommandCSMode final
for (auto *ml : mlocks)
{
ChannelMode *cm = ModeManager::FindChannelModeByName(ml->name);
if (cm && cm->CanSet(source.GetUser()))
if (cm && cm->CanSet(source.GetUser(), ci->c))
modelocks->RemoveMLock(cm, ml->set, ml->param);
}
}
@@ -320,7 +320,7 @@ class CommandCSMode final
source.Reply(_("Unknown mode character %c ignored."), mode);
break;
}
else if (u && !cm->CanSet(u))
else if (u && !cm->CanSet(u, ci->c))
{
source.Reply(_("You may not (un)lock mode %c."), mode);
break;
@@ -412,7 +412,7 @@ class CommandCSMode final
source.Reply(_("Unknown mode character %c ignored."), mode);
break;
}
else if (u && !cm->CanSet(u))
else if (u && !cm->CanSet(u, ci->c))
{
source.Reply(_("You may not (un)lock mode %c."), mode);
break;
@@ -508,7 +508,7 @@ class CommandCSMode final
{
ChannelMode *cm = ModeManager::GetChannelModes()[j];
if (!u || cm->CanSet(u) || can_override)
if (!u || cm->CanSet(u, ci->c) || can_override)
{
if (cm->type == MODE_REGULAR || (!adding && cm->type == MODE_PARAM))
{
@@ -524,7 +524,7 @@ class CommandCSMode final
if (adding == -1)
break;
ChannelMode *cm = ModeManager::FindChannelModeByChar(mode);
if (!cm || (u && !cm->CanSet(u) && !can_override))
if (!cm || (u && !cm->CanSet(u, ci->c) && !can_override))
continue;
switch (cm->type)
{
+1 -1
View File
@@ -1333,7 +1333,7 @@ public:
if (persist.HasExt(ci))
info.AddOption(_("Persistent"));
if (noexpire.HasExt(ci))
info.AddOption(_("No expire"));
info.AddOption(_("No expiry"));
if (keep_modes.HasExt(ci))
info.AddOption(_("Keep modes"));
if (noautoop.HasExt(ci))
+8 -8
View File
@@ -134,9 +134,9 @@ struct UserData final
Anope::string info_adder;
Anope::string info_message;
time_t info_ts = 0;
Anope::string last_mask;
Anope::string last_quit;
Anope::string last_real_mask;
Anope::string last_userhost;
Anope::string last_userhost_real;
bool noexpire = false;
bool protect = false;
std::optional<time_t> protectafter;
@@ -1146,9 +1146,9 @@ private:
else if (key == "private:freeze:timestamp")
data->suspend_ts = Anope::Convert<time_t>(value, 0);
else if (key == "private:host:actual")
data->last_real_mask = value;
data->last_userhost_real = value;
else if (key == "private:host:vhost")
data->last_mask = value;
data->last_userhost = value;
else if (key == "private:lastquit:message")
data->last_quit = value;
else if (key == "private:loginfail:failnum")
@@ -1314,14 +1314,14 @@ private:
auto *data = userdata.Get(nc);
if (data)
{
if (!data->last_mask.empty())
na->last_usermask = data->last_mask;
if (!data->last_userhost.empty())
na->last_userhost = data->last_userhost;
if (!data->last_quit.empty())
na->last_quit = data->last_quit;
if (!data->last_real_mask.empty())
na->last_realhost = data->last_real_mask;
if (!data->last_userhost_real.empty())
na->last_userhost_real = data->last_userhost_real;
if (data->noexpire)
na->Extend<bool>("NS_NO_EXPIRE");
+4 -4
View File
@@ -616,11 +616,11 @@ static void LoadNicks()
for (int i = 0; i < 1024; ++i)
for (int c; (c = getc_db(f)) == 1;)
{
Anope::string nick, last_usermask, last_realname, last_quit;
Anope::string nick, last_userhost, last_realname, last_quit;
time_t registered, last_seen;
READ(read_string(nick, f));
READ(read_string(last_usermask, f));
READ(read_string(last_userhost, f));
READ(read_string(last_realname, f));
READ(read_string(last_quit, f));
@@ -658,7 +658,7 @@ static void LoadNicks()
ForbidData *d = forbid->CreateForbid();
d->mask = nc->display;
d->creator = last_usermask;
d->creator = last_userhost;
d->reason = last_realname;
d->expires = 0;
d->created = 0;
@@ -669,7 +669,7 @@ static void LoadNicks()
}
auto *na = new NickAlias(nick, nc);
na->last_usermask = last_usermask;
na->last_userhost = last_userhost;
na->last_realname = last_realname;
na->last_quit = last_quit;
na->registered = registered;
+4 -11
View File
@@ -77,11 +77,6 @@ struct HostRequestTypeImpl final
class CommandHSRequest final
: public Command
{
static bool isvalidchar(char c)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-';
}
public:
CommandHSRequest(Module *creator) : Command(creator, "hostserv/request", 1, 1)
{
@@ -142,13 +137,11 @@ public:
source.Reply(HOST_NO_VIDENT);
return;
}
for (const auto &chr : user)
if (!IRCD->IsIdentValid(user))
{
if (!isvalidchar(chr))
{
source.Reply(HOST_SET_IDENT_ERROR);
return;
}
source.Reply(HOST_SET_IDENT_ERROR);
return;
}
}
+8 -3
View File
@@ -224,16 +224,21 @@ public:
auto protect = protectafter ? *protectafter : block.Get<time_t>("defaultprotect", "1m");
protect = std::clamp(protect, block.Get<time_t>("minprotect", "10s"), block.Get<time_t>("maxprotect", "10m"));
u->SendMessage(NickServ, _(
"This nickname is registered and has protection enabled. If it belongs to you, "
"type \002%s\032\037password\037\002 to identify to your account."
),
NickServ->GetQueryCommand("nickserv/identify", u->nick).c_str()
);
if (protect)
{
u->SendMessage(NickServ, NICK_IS_SECURE, NickServ->GetQueryCommand("nickserv/identify").c_str());
u->SendMessage(NickServ, _("If you do not change within %s, I will change your nick."),
u->SendMessage(NickServ, _("Your nickname will be changed in %s if you do not identify."),
Anope::Duration(protect, u->Account()).c_str());
new NickServCollide(this, this, u, na, protect);
}
else
{
u->SendMessage(NickServ, FORCENICKCHANGE_NOW);
this->Collide(u, na);
}
}
+1 -1
View File
@@ -55,7 +55,7 @@ public:
if (u != NULL)
{
na->last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost();
na->last_userhost = u->GetIdent() + "@" + u->GetDisplayedHost();
na->last_realname = u->realname;
}
else
+27 -20
View File
@@ -93,13 +93,13 @@ public:
if (nick_online)
{
bool shown = false;
if (show_hidden && !na->last_realhost.empty())
if (show_hidden && !na->last_userhost_real.empty())
{
info[_("Online from")] = na->last_realhost;
info[_("Online from")] = na->last_userhost_real;
shown = true;
}
if ((show_hidden || !na->nc->HasExt("HIDE_MASK")) && (!shown || na->last_usermask != na->last_realhost))
info[_("Online from")] = na->last_usermask;
if ((show_hidden || !na->nc->HasExt("HIDE_MASK")) && (!shown || na->last_userhost != na->last_userhost_real))
info[_("Online from")] = na->last_userhost;
else
source.Reply(_("%s is currently online."), na->nick.c_str());
}
@@ -108,22 +108,24 @@ public:
Anope::string shown;
if (show_hidden || !na->nc->HasExt("HIDE_MASK"))
{
info[_("Last seen address")] = na->last_usermask;
shown = na->last_usermask;
info[_("Last seen mask")] = na->last_userhost;
shown = na->last_userhost;
}
if (show_hidden && !na->last_realhost.empty() && na->last_realhost != shown)
info[_("Last seen address")] = na->last_realhost;
if (show_hidden && !na->last_userhost_real.empty() && na->last_userhost_real != shown)
info[_("Last seen mask")] = na->last_userhost_real;
}
info[_("Account registered")] = Anope::strftime(na->nc->registered, source.GetAccount());
info[_("Nick registered")] = Anope::strftime(na->registered, source.GetAccount());
if (!nick_online)
{
info[_("Last seen")] = Anope::strftime(na->last_seen, source.GetAccount());
if (!na->last_quit.empty() && (show_hidden || !na->nc->HasExt("HIDE_QUIT")))
info[_("Last quit message")] = na->last_quit;
if (!na->last_quit.empty() && (show_hidden || !na->nc->HasExt("HIDE_QUIT")))
info[_("Last quit message")] = na->last_quit;
}
if (!na->nc->email.empty() && (show_hidden || !na->nc->HasExt("HIDE_EMAIL")))
info[_("Email address")] = na->nc->email;
@@ -167,7 +169,7 @@ public:
CommandNSSetHide(Module *creator, const Anope::string &sname = "nickserv/set/hide", size_t min = 2) : Command(creator, sname, min, min + 1)
{
this->SetDesc(_("Hide certain pieces of nickname information"));
this->SetSyntax("{EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}");
this->SetSyntax("{EMAIL | STATUS | MASK | QUIT} {ON | OFF}");
}
void Run(CommandSource &source, const Anope::string &user, const Anope::string &param, const Anope::string &arg)
@@ -199,7 +201,7 @@ public:
onmsg = _("The email address of \002%s\002 will now be hidden from %s INFO displays.");
offmsg = _("The email address of \002%s\002 will now be shown in %s INFO displays.");
}
else if (param.equals_ci("USERMASK"))
else if (param.equals_ci("MASK"))
{
flag = "HIDE_MASK";
onmsg = _("The last seen user@host mask of \002%s\002 will now be hidden from %s INFO displays.");
@@ -252,7 +254,7 @@ public:
"Allows you to prevent certain pieces of information from "
"being displayed when someone does a %s\032\002INFO\002 on your "
"nick. You can hide your email address\032(\002EMAIL\002), last seen "
"user@host mask (\002USERMASK\002), your services access status "
"user@host mask (\002MASK\002), your services access status "
"(\002STATUS\002) and last quit message (\002QUIT\002). "
"The second parameter specifies whether the information should "
"be displayed (\002OFF\002) or hidden (\002ON\002)."
@@ -268,7 +270,7 @@ class CommandNSSASetHide final
public:
CommandNSSASetHide(Module *creator) : CommandNSSetHide(creator, "nickserv/saset/hide", 3)
{
this->SetSyntax(_("\037nickname\037 {EMAIL | STATUS | USERMASK | QUIT} {ON | OFF}"));
this->SetSyntax(_("\037nickname\037 {EMAIL | STATUS | MASK | QUIT} {ON | OFF}"));
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
@@ -285,7 +287,7 @@ public:
"Allows you to prevent certain pieces of information from "
"being displayed when someone does a %s\032\002INFO\002 on the "
"nick. You can hide the email address (\002EMAIL\002), last seen "
"user@host mask (\002USERMASK\002), the services access status "
"user@host mask (\002MASK\002), the services access status "
"(\002STATUS\002) and last quit message (\002QUIT\002). "
"The second parameter specifies whether the information should "
"be displayed (\002OFF\002) or hidden (\002ON\002)."
@@ -303,13 +305,18 @@ class NSInfo final
CommandNSSetHide commandnssethide;
CommandNSSASetHide commandnssasethide;
SerializableExtensibleItem<bool> hide_email, hide_usermask, hide_status, hide_quit;
SerializableExtensibleItem<bool> hide_email, hide_mask, hide_status, hide_quit;
public:
NSInfo(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
commandnsinfo(this), commandnssethide(this), commandnssasethide(this),
hide_email(this, "HIDE_EMAIL"), hide_usermask(this, "HIDE_MASK"), hide_status(this, "HIDE_STATUS"),
hide_quit(this, "HIDE_QUIT")
NSInfo(const Anope::string &modname, const Anope::string &creator)
: Module(modname, creator, VENDOR)
, commandnsinfo(this)
, commandnssethide(this)
, commandnssasethide(this)
, hide_email(this, "HIDE_EMAIL")
, hide_mask(this, "HIDE_MASK")
, hide_status(this, "HIDE_STATUS")
, hide_quit(this, "HIDE_QUIT")
{
}
+6 -6
View File
@@ -73,7 +73,7 @@ public:
mync = source.nc;
ListFormatter list(source.GetAccount());
list.AddColumn(_("Nick")).AddColumn(_("Last usermask"));
list.AddColumn(_("Nick")).AddColumn(_("Last mask"));
Anope::map<NickAlias *> ordered_map;
for (const auto &[nick, na] : *NickAliasList)
@@ -94,7 +94,7 @@ public:
/* We no longer compare the pattern against the output buffer.
* Instead we build a nice nick!user@host buffer to compare.
* The output is then generated separately. -TheShadow */
Anope::string buf = Anope::printf("%s!%s", na->nick.c_str(), !na->last_usermask.empty() ? na->last_usermask.c_str() : "*@*");
Anope::string buf = Anope::printf("%s!%s", na->nick.c_str(), !na->last_userhost.empty() ? na->last_userhost.c_str() : "*@*");
if (na->nick.equals_ci(pattern) || Anope::Match(buf, pattern, false, true))
{
if (((count + 1 >= from && count + 1 <= to) || (!from && !to)) && ++nnicks <= listmax)
@@ -106,13 +106,13 @@ public:
ListFormatter::ListEntry entry;
entry["Nick"] = (isnoexpire ? "!" : "") + na->nick;
if (na->nc->HasExt("HIDE_MASK") && !is_servadmin && na->nc != mync)
entry["Last usermask"] = Language::Translate(source.GetAccount(), _("[Hostname hidden]"));
entry["Last mask"] = Language::Translate(source.GetAccount(), _("[Hostname hidden]"));
else if (na->nc->HasExt("NS_SUSPENDED"))
entry["Last usermask"] = Language::Translate(source.GetAccount(), _("[Suspended]"));
entry["Last mask"] = Language::Translate(source.GetAccount(), _("[Suspended]"));
else if (na->nc->HasExt("UNCONFIRMED"))
entry["Last usermask"] = Language::Translate(source.GetAccount(), _("[Unconfirmed]"));
entry["Last mask"] = Language::Translate(source.GetAccount(), _("[Unconfirmed]"));
else
entry["Last usermask"] = na->last_usermask;
entry["Last mask"] = is_servadmin ? na->last_userhost_real : na->last_userhost;
list.AddEntry(entry);
}
++count;
+55 -21
View File
@@ -141,7 +141,7 @@ public:
if (u)
{
na->last_usermask = u->GetIdent() + "@" + u->GetDisplayedHost();
na->last_userhost = u->GetIdent() + "@" + u->GetDisplayedHost();
na->last_realname = u->realname;
}
else
@@ -351,9 +351,12 @@ class CommandNSResend final
: public Command
{
public:
CommandNSResend(Module *creator) : Command(creator, "nickserv/resend", 0, 0)
CommandNSResend(Module *creator)
: Command(creator, "nickserv/resend", 0, 1)
{
this->SetDesc(_("Resend registration confirmation email"));
this->SetSyntax(_("[\037nickname\037]"), [](auto &source) { return source.HasCommand("nickserv/resend"); });
this->AllowUnregistered(true);
}
void Execute(CommandSource &source, const std::vector<Anope::string> &params) override
@@ -364,27 +367,49 @@ public:
return;
}
const NickAlias *na = NickAlias::Find(source.GetNick());
if (na == NULL)
source.Reply(NICK_NOT_REGISTERED);
else if (na->nc != source.GetAccount() || !source.nc->HasExt("UNCONFIRMED"))
source.Reply(_("Your account is already confirmed."));
else
auto is_oper = false;
Anope::string nick;
if (!params.empty() && source.HasCommand("nickserv/resend"))
{
if (Anope::CurTime < source.nc->lastmail + Config->GetModule(this->owner).Get<time_t>("resenddelay"))
source.Reply(_("Cannot send mail now; please retry a little later."));
else if (SendRegmail(source.GetUser(), na, source.service))
{
na->nc->lastmail = Anope::CurTime;
source.Reply(_("Your confirmation code has been re-sent to %s."), na->nc->email.c_str());
Log(LOG_COMMAND, source, this) << "to resend registration confirmation code";
}
else
Log(this->owner) << "Unable to resend registration confirmation code for " << source.GetNick();
nick = params[0];
is_oper = true;
}
else if (source.nc)
nick = source.GetAccount()->display;
else
nick = source.GetNick();
const auto *na = NickAlias::Find(nick);
if (!na)
{
source.Reply(NICK_X_NOT_REGISTERED, nick.c_str());
return;
}
return;
NickCore *nc = na->nc;
if (!nc->HasExt("UNCONFIRMED"))
{
source.Reply(_("Nick \002%s\002 is already confirmed."), na->nick.c_str());
return;
}
if (!is_oper && Anope::CurTime < nc->lastmail + Config->GetModule(this->owner).Get<time_t>("resenddelay"))
{
source.Reply(_("Cannot send mail now; please retry a little later."));
return;
}
if (!SendRegmail(source.GetUser(), na, source.service))
{
Log(this->owner) << "Unable to resend registration confirmation code for " << na->nick;
return;
}
nc->lastmail = Anope::CurTime;
source.Reply(_("The confirmation code for \002%s\002 has been re-sent to %s."),
na->nick.c_str(), nc->email.c_str());
Log(nc == source.GetAccount() ? LOG_COMMAND : LOG_ADMIN, source, this) << "to resend the registration confirmation code for " << na->nick;
}
bool OnHelp(CommandSource &source, const Anope::string &subcommand) override
@@ -394,7 +419,16 @@ public:
this->SendSyntax(source);
source.Reply(" ");
source.Reply(_("This command will resend you the registration confirmation email."));
source.Reply(_("This command will resend a registration confirmation email."));
if (source.HasCommand("nickserv/resend"))
{
source.Reply(" ");
source.Reply(_(
"Additionally, Services Operators with the \037nickserv/resend\037 permission "
"can specify a nickname to resend a confirmation email for another account."
));
}
return true;
}
+1 -1
View File
@@ -648,7 +648,7 @@ public:
if (neverop.HasExt(na->nc))
info.AddOption(_("Never-op"));
if (noexpire.HasExt(na))
info.AddOption(_("No expire"));
info.AddOption(_("No expiry"));
}
void OnUserModeSet(const MessageSource &setter, User *u, const Anope::string &mname) override
+1 -1
View File
@@ -227,7 +227,7 @@ public:
for (const auto &[last_mode, last_data] : modes)
{
auto *um = ModeManager::FindUserModeByName(last_mode);
if (um && um->CanSet(nullptr) && norestore.find(um->mchar) == Anope::string::npos)
if (um && um->CanSet(nullptr, u) && norestore.find(um->mchar) == Anope::string::npos)
u->SetMode(nullptr, last_mode, last_data);
}
}
+1 -1
View File
@@ -450,7 +450,7 @@ public:
"\0371h30m\037) are not permitted. If a unit specifier is not "
"included, the default is days (so \037+30\037 by itself means 30 "
"days). To add an AKILL which does not expire, use \037+0\037. If the "
"usermask to be added starts with a \037+\037, an expiry time must "
"mask to be added starts with a \037+\037, an expiry time must "
"be given, even if it is the same as the default. The "
"current AKILL default expiry time can be found with the "
"\002STATS\032AKILL\002 command."
+1 -1
View File
@@ -23,7 +23,7 @@ class ChannelModeLargeBan final
public:
ChannelModeLargeBan(const Anope::string &mname, char modeChar) : ChannelMode(mname, modeChar) { }
bool CanSet(User *u) const override
bool CanSet(User *u, Channel *c) const override
{
return u && u->HasMode("OPER");
}
+1 -1
View File
@@ -749,7 +749,7 @@ public:
{
}
bool CanSet(User *u) const override
bool CanSet(User *u, Channel *c) const override
{
return false;
}
+2 -2
View File
@@ -247,12 +247,12 @@ namespace
bool has_help = source.service->commands.find("HELP") != source.service->commands.end();
if (has_help && similar.empty())
{
source.Reply(_("Unknown command \002%s\002. Type \"%s\" for help."), message.c_str(),
source.Reply(_("Unknown command \002%s\002. Type \002%s\002 for help."), message.c_str(),
source.service->GetQueryCommand("generic/help").c_str());
}
else if (has_help)
{
source.Reply(_("Unknown command \002%s\002. Did you mean \002%s\002? Type \"%s\" for help."),
source.Reply(_("Unknown command \002%s\002. Did you mean \002%s\002? Type \002%s\002 for help."),
message.c_str(), similar.c_str(), source.service->GetQueryCommand("generic/help").c_str());
}
else if (similar.empty())
+7 -12
View File
@@ -113,11 +113,6 @@ Mode::Mode(const Anope::string &mname, ModeClass mcl, char mch, ModeType mt) : n
{
}
bool Mode::CanSet(User *u) const
{
return true;
}
UserMode::UserMode(const Anope::string &un, char mch) : Mode(un, MC_USER, mch, MODE_REGULAR)
{
}
@@ -131,10 +126,10 @@ ChannelMode::ChannelMode(const Anope::string &cm, char mch) : Mode(cm, MC_CHANNE
{
}
bool ChannelMode::CanSet(User *u) const
bool ChannelMode::CanSet(User *u, Channel *c) const
{
EventReturn MOD_RESULT;
FOREACH_RESULT(OnCanSet, MOD_RESULT, (u, this));
FOREACH_RESULT(OnCanSet, MOD_RESULT, (u, c, this));
return MOD_RESULT != EVENT_STOP;
}
@@ -222,12 +217,12 @@ ChannelMode *ChannelModeVirtual<T>::Wrap(Anope::string &param)
template class ChannelModeVirtual<ChannelMode>;
template class ChannelModeVirtual<ChannelModeList>;
bool UserModeOperOnly::CanSet(User *u) const
bool UserModeOperOnly::CanSet(User *source, User *target) const
{
return u && u->HasMode("OPER");
return source && source->HasMode("OPER");
}
bool UserModeNoone::CanSet(User *u) const
bool UserModeNoone::CanSet(User *source, User *target) const
{
return false;
}
@@ -237,12 +232,12 @@ bool ChannelModeKey::IsValid(Anope::string &value) const
return !value.empty() && value.find(':') == Anope::string::npos && value.find(',') == Anope::string::npos;
}
bool ChannelModeOperOnly::CanSet(User *u) const
bool ChannelModeOperOnly::CanSet(User *u, Channel *c) const
{
return u && u->HasMode("OPER");
}
bool ChannelModeNoone::CanSet(User *u) const
bool ChannelModeNoone::CanSet(User *u, Channel *c) const
{
return false;
}
+16 -73
View File
@@ -20,6 +20,7 @@
#endif
#include <filesystem>
namespace fs = std::filesystem;
std::list<Module *> ModuleManager::Modules;
std::vector<Module *> ModuleManager::EventHandlers[I_SIZE];
@@ -32,77 +33,17 @@ void ModuleManager::CleanupRuntimeDirectory()
Log(LOG_DEBUG) << "Cleaning out Module run time directory (" << dirbuf << ") - this may take a moment, please wait";
try
{
for (const auto &entry : std::filesystem::directory_iterator(dirbuf.str()))
for (const auto &entry : fs::directory_iterator(dirbuf.str()))
{
if (entry.is_regular_file())
std::filesystem::remove(entry);
fs::remove(entry);
}
}
catch (const std::filesystem::filesystem_error &err)
catch (const fs::filesystem_error &err)
{
Log(LOG_DEBUG) << "Cannot open directory (" << dirbuf << "): " << err.what();
}
}
/**
* Copy the module from the modules folder to the runtime folder.
* This will prevent module updates while the modules is loaded from
* triggering a segfault, as the actual file in use will be in the
* runtime folder.
* @param name the name of the module to copy
* @param output the destination to copy the module to
* @return MOD_ERR_OK on success
*/
static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &output)
{
const auto input = Anope::ExpandModule(name + DLL_EXT);
struct stat s;
if (stat(input.c_str(), &s) == -1)
return MOD_ERR_NOEXIST;
else if (!S_ISREG(s.st_mode))
return MOD_ERR_NOEXIST;
std::ifstream source(input.c_str(), std::ios_base::in | std::ios_base::binary);
if (!source.is_open())
return MOD_ERR_NOEXIST;
char *tmp_output = strdup(output.c_str());
int target_fd = mkstemp(tmp_output);
if (target_fd == -1 || close(target_fd) == -1)
{
free(tmp_output);
source.close();
return MOD_ERR_FILE_IO;
}
output = tmp_output;
free(tmp_output);
Log(LOG_DEBUG_2) << "Runtime module location: " << output;
std::ofstream target(output.c_str(), std::ios_base::in | std::ios_base::binary);
if (!target.is_open())
{
source.close();
return MOD_ERR_FILE_IO;
}
int want = s.st_size;
char buffer[1024];
while (want > 0 && !source.fail() && !target.fail())
{
source.read(buffer, std::min(want, static_cast<int>(sizeof(buffer))));
int read_len = source.gcount();
target.write(buffer, read_len);
want -= read_len;
}
source.close();
target.close();
return !source.fail() && !target.fail() ? MOD_ERR_OK : MOD_ERR_FILE_IO;
}
#endif
/* This code was found online at https://web.archive.org/web/20180318184211/https://www.linuxjournal.com/article/3687#comment-26593
@@ -131,22 +72,24 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
Log(LOG_DEBUG) << "Trying to load module: " << modname;
const auto modpath = Anope::ExpandModule(modname + DLL_EXT);
std::error_code ec;
if (!fs::exists(modpath.str()) || ec)
{
Log(LOG_TERMINAL) << "Error while loading " << modname << ": file does not exist";
return MOD_ERR_NOEXIST;
}
#ifdef _WIN32
/* Generate the filename for the temporary copy of the module */
auto pbuf = Anope::ExpandData("runtime/" + modname + DLL_EXT ".XXXXXX");
/* Don't skip return value checking! -GD */
ModuleReturn ret = moduleCopyFile(modname, pbuf);
if (ret != MOD_ERR_OK)
if (!fs::copy_file(modpath.str(), pbuf.str(), fs::copy_options::overwrite_existing, ec) || ec)
{
if (ret == MOD_ERR_NOEXIST)
Log(LOG_TERMINAL) << "Error while loading " << modname << " (file does not exist)";
else if (ret == MOD_ERR_FILE_IO)
Log(LOG_TERMINAL) << "Error while loading " << modname << " (file IO error, check file permissions and diskspace)";
return ret;
Log(LOG_TERMINAL) << "Error while loading " << modname << ": " << ec.message();
return MOD_ERR_FILE_IO;
}
#else
const auto pbuf = Anope::ExpandModule(modname + DLL_EXT);
const auto pbuf = modpath;
#endif
dlerror();
+10 -5
View File
@@ -156,8 +156,8 @@ void NickAlias::Type::Serialize(Serializable *obj, Serialize::Data &data) const
data.Store("nick", na->nick);
data.Store("last_quit", na->last_quit);
data.Store("last_realname", na->last_realname);
data.Store("last_usermask", na->last_usermask);
data.Store("last_realhost", na->last_realhost);
data.Store("last_userhost", na->last_userhost);
data.Store("last_userhost_real", na->last_userhost_real);
data.Store("registered", na->registered);
data.Store("last_seen", na->last_seen);
data.Store("ncid", na->nc->GetId());
@@ -209,8 +209,8 @@ Serializable *NickAlias::Type::Unserialize(Serializable *obj, Serialize::Data &d
data["last_quit"] >> na->last_quit;
data["last_realname"] >> na->last_realname;
data["last_usermask"] >> na->last_usermask;
data["last_realhost"] >> na->last_realhost;
data["last_userhost"] >> na->last_userhost;
data["last_userhost_real"] >> na->last_userhost_real;
data["registered"] >> na->registered;
data["last_seen"] >> na->last_seen;
@@ -235,7 +235,12 @@ Serializable *NickAlias::Type::Unserialize(Serializable *obj, Serialize::Data &d
// End 1.9 compatibility.
// Begin 2.0 compatibility.
if (!na->registered)
if (na->last_userhost.empty())
data["last_usermask"] >> na->last_userhost;
if (na->last_userhost_real.empty())
data["last_realhost"] >> na->last_userhost_real;
if (na->registered == Anope::CurTime)
data["time_registered"] >> na->registered;
if (na->registered < na->nc->registered)
na->nc->registered = na->registered;
+1 -1
View File
@@ -181,7 +181,7 @@ Serializable *NickCore::Type::Unserialize(Serializable *obj, Serialize::Data &da
// End 2.0 compatibility.
// Begin 2.1 compatibility.
if (!nc->registered)
if (nc->registered == Anope::CurTime)
data["time_registered"] >> nc->registered;
// End 2.1 compatibility.
+1 -1
View File
@@ -329,7 +329,7 @@ Serializable *ChannelInfo::Type::Unserialize(Serializable *obj, Serialize::Data
// End 1.9 compatibility.
// Begin 2.0 compatibility.
if (!ci->registered)
if (ci->registered == Anope::CurTime)
data["time_registered"] >> ci->registered;
// End 2.0 compatibility.
+4 -6
View File
@@ -376,8 +376,8 @@ void User::Identify(NickAlias *na)
{
if (this->nick.equals_ci(na->nick))
{
na->last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost();
na->last_realhost = this->GetIdent() + "@" + this->host;
na->last_userhost = this->GetIdent() + "@" + this->GetDisplayedHost();
na->last_userhost_real = this->GetIdent() + "@" + this->host;
na->last_realname = this->realname;
na->last_seen = Anope::CurTime;
}
@@ -534,10 +534,8 @@ void User::UpdateHost()
NickAlias *na = NickAlias::Find(this->nick);
if (na && this->IsIdentified(true))
{
Anope::string last_usermask = this->GetIdent() + "@" + this->GetDisplayedHost();
Anope::string last_realhost = this->GetIdent() + "@" + this->host;
na->last_usermask = last_usermask;
na->last_realhost = last_realhost;
na->last_userhost = this->GetIdent() + "@" + this->GetDisplayedHost();
na->last_userhost_real = this->GetIdent() + "@" + this->host;
// This is called on signon, and if users are introduced with an account it won't update
na->last_realname = this->realname;
}
+1 -1
View File
@@ -2,5 +2,5 @@
VERSION_MAJOR=2
VERSION_MINOR=1
VERSION_PATCH=16
VERSION_PATCH=17
VERSION_EXTRA=""
-363
View File
@@ -1,363 +0,0 @@
/*
* Config.cs - Windows Configuration
*
* (C) 2003-2025 Anope Team
* Contact us at team@anope.org
*
* This program is free but copyrighted software; see the file COPYING for
* details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* Written by Scott <stealtharcher.scott@gmail.com>
* Written by Adam <Adam@anope.org>
* Cleaned up by Naram Qashat <cyberbotx@anope.org>
*
* Compile with: csc /out:../../Config.exe /win32icon:anope-icon.ico Config.cs
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
namespace Config
{
class Config
{
static string ExecutablePath, InstallDirectory, ExtraIncludeDirs, ExtraLibDirs, ExtraArguments;
static bool UseNMake = true, BuildDebug = false;
static bool CheckResponse(string InstallerResponse)
{
if (string.Compare(InstallerResponse, "yes", true) == 0 || string.Compare(InstallerResponse, "y", true) == 0)
return true;
return false;
}
static bool LoadCache()
{
try
{
string[] cache = File.ReadAllLines(string.Format(@"{0}\config.cache", ExecutablePath));
if (cache.Length > 0)
Console.WriteLine("Using defaults from config.cache");
foreach (string line in cache)
{
int e = line.IndexOf('=');
string name = line.Substring(0, e);
string value = line.Substring(e + 1);
if (name == "INSTDIR")
InstallDirectory = value;
else if (name == "DEBUG")
BuildDebug = CheckResponse(value);
else if (name == "USENMAKE")
UseNMake = CheckResponse(value);
else if (name == "EXTRAINCLUDE")
ExtraIncludeDirs = value;
else if (name == "EXTRALIBS")
ExtraLibDirs = value;
else if (name == "EXTRAARGS")
ExtraArguments = value;
}
return true;
}
catch (Exception)
{
}
return false;
}
static void SaveCache()
{
using (TextWriter tw = new StreamWriter(string.Format(@"{0}\config.cache", ExecutablePath)))
{
tw.WriteLine("INSTDIR={0}", InstallDirectory);
tw.WriteLine("DEBUG={0}", BuildDebug ? "yes" : "no");
tw.WriteLine("USENMAKE={0}", UseNMake ? "yes" : "no");
tw.WriteLine("EXTRAINCLUDE={0}", ExtraIncludeDirs);
tw.WriteLine("EXTRALIBS={0}", ExtraLibDirs);
tw.WriteLine("EXTRAARGS={0}", ExtraArguments);
}
}
static string HandleCache(int i)
{
switch (i)
{
case 0:
Console.Write("[{0}] ", InstallDirectory);
return InstallDirectory;
case 1:
Console.Write("[{0}] ", UseNMake ? "yes" : "no");
return UseNMake ? "yes" : "no";
case 2:
Console.Write("[{0}] ", BuildDebug ? "yes" : "no");
return BuildDebug ? "yes" : "no";
case 3:
Console.Write("[{0}] ", ExtraIncludeDirs);
return ExtraIncludeDirs;
case 4:
Console.Write("[{0}] ", ExtraLibDirs);
return ExtraLibDirs;
case 5:
Console.Write("[{0}] ", ExtraArguments);
return ExtraArguments;
default:
break;
}
return null;
}
static string FindAnopeVersion()
{
if (!File.Exists(string.Format(@"{0}\src\version.sh", ExecutablePath)))
return "Unknown";
Dictionary<string, string> versions = new Dictionary<string, string>();
string[] versionfile = File.ReadAllLines(string.Format(@"{0}\src\version.sh", ExecutablePath));
foreach (string line in versionfile)
if (line.StartsWith("VERSION_"))
{
string key = line.Split('_')[1].Split('=')[0];
if (!versions.ContainsKey(key))
versions.Add(key, line.Split('=')[1].Replace("\"", "").Replace("\'", ""));
}
try
{
if (versions.ContainsKey("BUILD"))
return string.Format("{0}.{1}.{2}.{3}{4}", versions["MAJOR"], versions["MINOR"], versions["PATCH"], versions["BUILD"], versions["EXTRA"]);
else
return string.Format("{0}.{1}.{2}{3}", versions["MAJOR"], versions["MINOR"], versions["PATCH"], versions["EXTRA"]);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return "Unknown";
}
}
static void RunCMake(string cMake)
{
Console.WriteLine("cmake {0}", cMake);
try
{
ProcessStartInfo processStartInfo = new ProcessStartInfo("cmake")
{
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
Arguments = cMake
};
Process pCMake = Process.Start(processStartInfo);
StreamReader stdout = pCMake.StandardOutput, stderr = pCMake.StandardError;
string stdoutr, stderrr;
List<string> errors = new List<string>();
while (!pCMake.HasExited)
{
if ((stdoutr = stdout.ReadLine()) != null)
Console.WriteLine(stdoutr);
if ((stderrr = stderr.ReadLine()) != null)
errors.Add(stderrr);
}
foreach (string error in errors)
Console.WriteLine(error);
Console.WriteLine();
if (pCMake.ExitCode == 0)
{
if (UseNMake)
Console.WriteLine("To compile Anope, run 'nmake'. To install, run 'nmake install'");
else
Console.WriteLine("To compile Anope, open Anope.sln and build the solution. To install, do a build on the INSTALL project");
}
else
Console.WriteLine("There was an error attempting to run CMake! Check the above error message, and contact the Anope team if you are unsure how to proceed.");
}
catch (Exception e)
{
Console.WriteLine();
Console.WriteLine(DateTime.UtcNow + " UTC: " + e.Message);
Console.WriteLine("There was an error attempting to run CMake! Check the above error message, and contact the Anope team if you are unsure how to proceed.");
}
}
static int Main(string[] args)
{
bool IgnoreCache = false, NoIntro = false, DoQuick = false;
if (args.Length > 0)
{
if (args[0] == "--help")
{
Console.WriteLine("Config utility for Anope");
Console.WriteLine("------------------------");
Console.WriteLine("Syntax: .\\Config.exe [options]");
Console.WriteLine("-nocache Ignore settings saved in config.cache");
Console.WriteLine("-nointro Skip intro (disclaimer, etc)");
Console.WriteLine("-quick or -q Skip questions, go straight to cmake");
return 0;
}
else if (args[0] == "-nocache")
IgnoreCache = true;
else if (args[0] == "-nointro")
NoIntro = true;
else if (args[0] == "-quick" || args[0] == "-q")
DoQuick = true;
}
ExecutablePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string AnopeVersion = FindAnopeVersion();
if (!NoIntro && File.Exists(string.Format(@"{0}\.BANNER", ExecutablePath)))
Console.WriteLine(File.ReadAllText(string.Format(@"{0}\.BANNER", ExecutablePath)).Replace("CURVER", AnopeVersion).Replace("For more options type SOURCE_DIR/Config --help", ""));
Console.WriteLine("Press Enter to begin");
Console.WriteLine();
Console.ReadKey();
bool UseCache = false;
if (DoQuick || !IgnoreCache)
{
UseCache = LoadCache();
if (DoQuick && !UseCache)
{
Console.WriteLine("Can't find cache file (config.cache), aborting...");
return 1;
}
}
if (!DoQuick)
{
List<string> InstallerQuestions = new List<string>()
{
"Where do you want Anope to be installed?",
"Would you like to build using NMake instead of using Visual Studio?\r\nNOTE: If you decide to use NMake, you must be in an environment where\r\nNMake can function, such as the Visual Studio command line. If you say\r\nyes to this while not in an environment that can run NMake, it can\r\ncause the CMake configuration to enter an endless loop. [y/n]",
"Would you like to build a debug version of Anope? [y/n]",
"Are there any extra include directories you wish to use?\nYou may only need to do this if CMake is unable to locate missing dependencies without hints.\nSeparate directories with semicolons and use slashes (aka /) instead of backslashes (aka \\).\nIf you need no extra include directories, enter NONE in all caps.",
"Are there any extra library directories you wish to use?\nYou may only need to do this if CMake is unable to locate missing dependencies without hints.\nSeparate directories with semicolons and use slashes (aka /) instead of backslashes (aka \\).\nIf you need no extra library directories, enter NONE in all caps.",
"Are there any extra arguments you wish to pass to CMake?\nIf you need no extra arguments to CMake, enter NONE in all caps."
};
for (int i = 0; i < InstallerQuestions.Count; ++i)
{
Console.WriteLine(InstallerQuestions[i]);
string CacheResponse = null;
if (UseCache)
CacheResponse = HandleCache(i);
string InstallerResponse = Console.ReadLine();
Console.WriteLine();
if (!string.IsNullOrWhiteSpace(CacheResponse) && string.IsNullOrWhiteSpace(InstallerResponse))
InstallerResponse = CacheResponse;
// Question 4+ are optional
if (i < 3 && string.IsNullOrWhiteSpace(InstallerResponse))
{
Console.WriteLine("Invalid option");
--i;
continue;
}
switch (i)
{
case 0:
if (!Directory.Exists(InstallerResponse))
{
Console.WriteLine("Directory does not exist! Creating directory.");
Console.WriteLine();
try
{
Directory.CreateDirectory(InstallerResponse);
InstallDirectory = InstallerResponse;
}
catch (Exception e)
{
Console.WriteLine("Unable to create directory: " + e.Message);
--i;
}
}
else if (File.Exists(InstallerResponse + @"\include\services.h"))
{
Console.WriteLine("You cannot use the Anope source directory as the target directory!");
--i;
}
else
InstallDirectory = InstallerResponse;
break;
case 1:
UseNMake = CheckResponse(InstallerResponse);
if (UseNMake)
++i;
break;
case 2:
BuildDebug = CheckResponse(InstallerResponse);
break;
case 3:
if (InstallerResponse == "NONE")
ExtraIncludeDirs = null;
else
ExtraIncludeDirs = InstallerResponse;
break;
case 4:
if (InstallerResponse == "NONE")
ExtraLibDirs = null;
else
ExtraLibDirs = InstallerResponse;
break;
case 5:
if (InstallerResponse == "NONE")
ExtraArguments = null;
else
ExtraArguments = InstallerResponse;
break;
default:
break;
}
}
}
Console.WriteLine("Anope will be compiled with the following options:");
Console.WriteLine("Install directory: {0}", InstallDirectory);
Console.WriteLine("Use NMake: {0}", UseNMake ? "Yes" : "No");
Console.WriteLine("Build debug: {0}", BuildDebug ? "Yes" : "No");
Console.WriteLine("Anope Version: {0}", AnopeVersion);
Console.WriteLine("Extra Include Directories: {0}", ExtraIncludeDirs);
Console.WriteLine("Extra Library Directories: {0}", ExtraLibDirs);
Console.WriteLine("Extra Arguments: {0}", ExtraArguments);
Console.WriteLine("Press Enter to continue...");
Console.ReadKey();
SaveCache();
if (!string.IsNullOrWhiteSpace(ExtraIncludeDirs))
ExtraIncludeDirs = string.Format("-DEXTRA_INCLUDE:STRING={0} ", ExtraIncludeDirs);
else
ExtraIncludeDirs = "";
if (!string.IsNullOrWhiteSpace(ExtraLibDirs))
ExtraLibDirs = string.Format("-DEXTRA_LIBS:STRING={0} ", ExtraLibDirs);
else
ExtraLibDirs = "";
if (!string.IsNullOrWhiteSpace(ExtraArguments))
ExtraArguments += " ";
else
ExtraArguments = "";
InstallDirectory = "-DINSTDIR:STRING=\"" + InstallDirectory.Replace('\\', '/') + "\" ";
string NMake = UseNMake ? "-G\"NMake Makefiles\" " : "";
string Debug = BuildDebug ? "-DCMAKE_BUILD_TYPE:STRING=DEBUG " : "-DCMAKE_BUILD_TYPE:STRING=RELEASE ";
string cMake = InstallDirectory + NMake + Debug + ExtraIncludeDirs + ExtraLibDirs + ExtraArguments + "\"" + ExecutablePath.Replace('\\', '/') + "\"";
RunCMake(cMake);
return 0;
}
}
}
-1
View File
@@ -67,7 +67,6 @@ extern CoreExport void OnShutdown();
extern CoreExport USHORT WindowsGetLanguage(const Anope::string &lang);
extern int setenv(const char *name, const char *value, int overwrite);
extern int unsetenv(const char *name);
extern int mkstemp(char *input);
#endif // _WIN32
#endif // WINDOWS_H
-13
View File
@@ -71,17 +71,4 @@ int unsetenv(const char *name)
return SetEnvironmentVariable(name, NULL);
}
int mkstemp(char *input)
{
input = _mktemp(input);
if (input == NULL)
{
errno = EEXIST;
return -1;
}
int fd = open(input, O_WRONLY | O_CREAT, S_IREAD | S_IWRITE);
return fd;
}
#endif