/* nickserv.c - Nick/authentication service
- * Copyright 2000-2004 srvx Development Team
+ * Copyright 2000-2006 srvx Development Team
*
- * This program is free software; you can redistribute it and/or modify
+ * This file is part of srvx.
+ *
+ * srvx is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version. Important limitations are
- * listed in the COPYING file that accompanies this software.
+ * (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, email srvx-maintainers@srvx.net.
+ * along with srvx; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include "chanserv.h"
#include "modcmd.h"
#include "opserv.h" /* for gag_create(), opserv_bad_channel() */
#include "saxdb.h"
-#include "sendmail.h"
+#include "mail.h"
#include "timeq.h"
#ifdef HAVE_REGEX_H
-#include <regex.h>
+# include <regex.h>
+#else
+# include "rx/rxposix.h"
#endif
#define NICKSERV_CONF_NAME "services/nickserv"
#define KEY_DB_BACKUP_FREQ "db_backup_freq"
#define KEY_MODOPER_LEVEL "modoper_level"
#define KEY_SET_EPITHET_LEVEL "set_epithet_level"
+#define KEY_SET_TITLE_LEVEL "set_title_level"
+#define KEY_SET_FAKEHOST_LEVEL "set_fakehost_level"
+#define KEY_TITLEHOST_SUFFIX "titlehost_suffix"
#define KEY_FLAG_LEVELS "flag_levels"
-#define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
+#define KEY_HANDLE_EXPIRE_FREQ "handle_expire_freq"
#define KEY_ACCOUNT_EXPIRE_FREQ "account_expire_freq"
-#define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
+#define KEY_HANDLE_EXPIRE_DELAY "handle_expire_delay"
#define KEY_ACCOUNT_EXPIRE_DELAY "account_expire_delay"
#define KEY_NOCHAN_HANDLE_EXPIRE_DELAY "nochan_handle_expire_delay"
#define KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY "nochan_account_expire_delay"
#define KEY_COOKIE_TIMEOUT "cookie_timeout"
#define KEY_ACCOUNTS_PER_EMAIL "accounts_per_email"
#define KEY_EMAIL_SEARCH_LEVEL "email_search_level"
+#define KEY_OUNREGISTER_INACTIVE "ounregister_inactive"
+#define KEY_OUNREGISTER_FLAGS "ounregister_flags"
#define KEY_ID "id"
#define KEY_PASSWD "passwd"
#define KEY_ALLOWAUTH "allowauth"
#define KEY_EPITHET "epithet"
#define KEY_TABLE_WIDTH "table_width"
-#define KEY_ANNOUNCEMENTS "announcements"
#define KEY_MAXLOGINS "maxlogins"
+#define KEY_FAKEHOST "fakehost"
+#define KEY_NOTES "notes"
+#define KEY_NOTE_EXPIRES "expires"
+#define KEY_NOTE_SET "set"
+#define KEY_NOTE_SETTER "setter"
+#define KEY_NOTE_NOTE "note"
+#define KEY_KARMA "karma"
-#define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
+#define NICKSERV_VALID_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
#define NICKSERV_FUNC(NAME) MODCMD_FUNC(NAME)
#define OPTION_FUNC(NAME) int NAME(struct userNode *user, struct handle_info *hi, UNUSED_ARG(unsigned int override), unsigned int argc, char *argv[])
{ "NSMSG_MUST_TIME_OUT", "You must wait for cookies of that type to time out." },
{ "NSMSG_ATE_COOKIE", "I ate the cookie for your account. You may now have another." },
{ "NSMSG_USE_RENAME", "You are already authenticated to account $b%s$b -- contact the support staff to rename your account." },
+ { "NSMSG_ALREADY_REGISTERING", "You have already used $bREGISTER$b once this session; you may not use it again." },
{ "NSMSG_REGISTER_BAD_NICKMASK", "Could not recognize $b%s$b as either a current nick or a hostmask." },
{ "NSMSG_NICK_NOT_REGISTERED", "Nick $b%s$b has not been registered to any account." },
{ "NSMSG_HANDLE_NOT_FOUND", "Could not find your account -- did you register yet?" },
{ "NSMSG_ALREADY_AUTHED", "You are already authed to account $b%s$b; you must reconnect to auth to a different account." },
- { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %s)" },
+ { "NSMSG_USE_AUTHCOOKIE", "Your hostmask is not valid for account $b%1$s$b. Please use the $bauthcookie$b command to grant yourself access. (/msg $S authcookie %1$s)" },
{ "NSMSG_HOSTMASK_INVALID", "Your hostmask is not valid for account $b%s$b." },
{ "NSMSG_USER_IS_SERVICE", "$b%s$b is a network service; you can only use that command on real users." },
{ "NSMSG_USER_PREV_AUTH", "$b%s$b is already authenticated." },
{ "NSMSG_STAMPED_AUTH", "You have already authenticated to an account once this session; you may not authenticate to another." },
{ "NSMSG_STAMPED_RESETPASS", "You have already authenticated to an account once this session; you may not reset your password to authenticate again." },
{ "NSMSG_STAMPED_AUTHCOOKIE", "You have already authenticated to an account once this session; you may not use a cookie to authenticate to another account." },
+ { "NSMSG_TITLE_INVALID", "Titles cannot contain any dots; please choose another." },
+ { "NSMSG_TITLE_TRUNCATED", "That title combined with the user's account name would result in a truncated host; please choose a shorter title." },
+ { "NSMSG_FAKEHOST_INVALID", "Fake hosts must be shorter than %d characters and cannot start with a dot." },
{ "NSMSG_HANDLEINFO_ON", "Account information for $b%s$b:" },
{ "NSMSG_HANDLEINFO_ID", " Account ID: %lu" },
{ "NSMSG_HANDLEINFO_REGGED", " Registered on: %s" },
{ "NSMSG_HANDLEINFO_LASTSEEN", " Last seen: %s" },
{ "NSMSG_HANDLEINFO_LASTSEEN_NOW", " Last seen: Right now!" },
+ { "NSMSG_HANDLEINFO_KARMA", " Karma: %d" },
{ "NSMSG_HANDLEINFO_VACATION", " On vacation." },
{ "NSMSG_HANDLEINFO_EMAIL_ADDR", " Email address: %s" },
{ "NSMSG_HANDLEINFO_COOKIE_ACTIVATION", " Cookie: There is currently an activation cookie issued for this account" },
{ "NSMSG_HANDLEINFO_INFOLINE", " Infoline: %s" },
{ "NSMSG_HANDLEINFO_FLAGS", " Flags: %s" },
{ "NSMSG_HANDLEINFO_EPITHET", " Epithet: %s" },
+ { "NSMSG_HANDLEINFO_FAKEHOST", " Fake host: %s" },
{ "NSMSG_HANDLEINFO_LAST_HOST", " Last quit hostmask: %s" },
+ { "NSMSG_HANDLEINFO_NO_NOTES", " Notes: None" },
+ { "NSMSG_HANDLEINFO_NOTE_EXPIRES", " Note %d (%s ago by %s, expires %s): %s" },
+ { "NSMSG_HANDLEINFO_NOTE", " Note %d (%s ago by %s): %s" },
{ "NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN", " Last quit hostmask: Unknown" },
{ "NSMSG_HANDLEINFO_NICKS", " Nickname(s): %s" },
{ "NSMSG_HANDLEINFO_MASKS", " Hostmask(s): %s" },
{ "NSMSG_USERINFO_AUTHED_AS", "$b%s$b is authenticated to account $b%s$b." },
{ "NSMSG_USERINFO_NOT_AUTHED", "$b%s$b is not authenticated to any account." },
{ "NSMSG_NICKINFO_OWNER", "Nick $b%s$b is owned by account $b%s$b." },
+ { "NSMSG_NOTE_EXPIRES", "Note %d (%s ago by %s, expires %s): %s" },
+ { "NSMSG_NOTE", "Note %d (%s ago by %s): %s" },
+ { "NSMSG_NOTE_COUNT", "%u note(s) for %s." },
{ "NSMSG_PASSWORD_INVALID", "Incorrect password; please try again." },
{ "NSMSG_PLEASE_SET_EMAIL", "We now require email addresses for users. Please use the $bset email$b command to set your email address!" },
{ "NSMSG_WEAK_PASSWORD", "WARNING: You are using a password that is considered weak (easy to guess). It is STRONGLY recommended you change it (now, if not sooner) by typing \"/msg $S@$s PASS oldpass newpass\" (with your current password and a new password)." },
{ "NSMSG_UNREGNICK_SUCCESS", "Nick $b%s$b has been unregistered." },
{ "NSMSG_UNREGISTER_SUCCESS", "Account $b%s$b has been unregistered." },
{ "NSMSG_UNREGISTER_NICKS_SUCCESS", "Account $b%s$b and all its nicks have been unregistered." },
+ { "NSMSG_UNREGISTER_MUST_FORCE", "Account $b%s$b is not inactive or has special flags set; use FORCE to unregister it." },
+ { "NSMSG_UNREGISTER_CANNOT_FORCE", "Account $b%s$b is not inactive or has special flags set; have an IRCOp use FORCE to unregister it." },
+ { "NSMSG_UNREGISTER_NODELETE", "Account $b%s$b is protected from unregistration." },
{ "NSMSG_HANDLE_STATS", "There are %d nicks registered to your account." },
{ "NSMSG_HANDLE_NONE", "You are not authenticated against any account." },
{ "NSMSG_GLOBAL_STATS", "There are %d accounts and %d nicks registered globally." },
{ "NSMSG_CANNOT_GHOST_USER", "$b%s$b is not authed to your account; you may not ghost-kill them." },
{ "NSMSG_GHOST_KILLED", "$b%s$b has been killed as a ghost." },
{ "NSMSG_ON_VACATION", "You are now on vacation. Your account will be preserved until you authenticate again." },
+ { "NSMSG_EXCESSIVE_DURATION", "$b%s$b is too long for this command." },
+ { "NSMSG_NOTE_ADDED", "Note $b%d$b added to $b%s$b." },
+ { "NSMSG_NOTE_REMOVED", "Note $b%d$b removed from $b%s$b." },
+ { "NSMSG_NO_SUCH_NOTE", "Account $b%s$b does not have a note with ID $b%d$b." },
{ "NSMSG_NO_ACCESS", "Access denied." },
{ "NSMSG_INVALID_FLAG", "$b%c$b is not a valid $N account flag." },
{ "NSMSG_SET_FLAG", "Applied flags $b%s$b to %s's $N account." },
{ "NSMSG_CLONE_AUTH", "Warning: %s (%s@%s) authed to your account." },
{ "NSMSG_SETTING_LIST", "$b$N account settings:$b" },
{ "NSMSG_INVALID_OPTION", "$b%s$b is an invalid account setting." },
- { "NSMSG_INVALID_ANNOUNCE", "$b%s$b is an announcements value." },
{ "NSMSG_SET_INFO", "$bINFO: $b%s" },
{ "NSMSG_SET_WIDTH", "$bWIDTH: $b%d" },
{ "NSMSG_SET_TABLEWIDTH", "$bTABLEWIDTH: $b%d" },
{ "NSMSG_SET_COLOR", "$bCOLOR: $b%s" },
{ "NSMSG_SET_PRIVMSG", "$bPRIVMSG: $b%s" },
{ "NSMSG_SET_STYLE", "$bSTYLE: $b%s" },
- { "NSMSG_SET_ANNOUNCEMENTS", "$bANNOUNCEMENTS: $b%s" },
{ "NSMSG_SET_PASSWORD", "$bPASSWORD: $b%s" },
{ "NSMSG_SET_FLAGS", "$bFLAGS: $b%s" },
{ "NSMSG_SET_EMAIL", "$bEMAIL: $b%s" },
{ "NSMSG_SET_LANGUAGE", "$bLANGUAGE: $b%s" },
{ "NSMSG_SET_LEVEL", "$bLEVEL: $b%d" },
{ "NSMSG_SET_EPITHET", "$bEPITHET: $b%s" },
+ { "NSMSG_SET_TITLE", "$bTITLE: $b%s" },
+ { "NSMSG_SET_FAKEHOST", "$bFAKEHOST: $b%s" },
+ { "NSMSG_INVALID_KARMA", "$b%s$b is not a valid karma modifier." },
+ { "NSMSG_SET_KARMA", "$bKARMA: $b%d$b" },
{ "NSEMAIL_ACTIVATION_SUBJECT", "Account verification for %s" },
- { "NSEMAIL_ACTIVATION_BODY", "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n %2$s\nTo verify your email address and complete the account registration, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
+ { "NSEMAIL_ACTIVATION_BODY", "This email has been sent to verify that this email address belongs to the person who tried to register an account on %1$s. Your cookie is:\n %2$s\nTo verify your email address and complete the account registration, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nThis command is only used once to complete your account registration, and never again. Once you have run this command, you will need to authenticate everytime you reconnect to the network. To do this, you will have to type this command every time you reconnect:\n /msg %3$s@%4$s AUTH %5$s your-password\n Please remember to fill in 'your-password' with the actual password you gave to us when you registered.\n\nIf you did NOT request this account, you do not need to do anything. Please contact the %1$s staff if you have questions, and be sure to check our website." },
{ "NSEMAIL_PASSWORD_CHANGE_SUBJECT", "Password change verification on %s" },
{ "NSEMAIL_PASSWORD_CHANGE_BODY", "This email has been sent to verify that you wish to change the password on your account %5$s. Your cookie is %2$s.\nTo complete the password change, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request your password to be changed, you do not need to do anything. Please contact the %1$s staff if you have questions." },
{ "NSEMAIL_EMAIL_CHANGE_SUBJECT", "Email address change verification for %s" },
{ "NSEMAIL_EMAIL_CHANGE_BODY_NEW", "This email has been sent to verify that your email address belongs to the same person as account %5$s on %1$s. The SECOND HALF of your cookie is %2$.*6$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s ?????%2$.*6$s\n(Replace the ????? with the FIRST HALF of the cookie, as sent to your OLD email address.)\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
{ "NSEMAIL_EMAIL_CHANGE_BODY_OLD", "This email has been sent to verify that you want to change your email for account %5$s on %1$s from this address to %7$s. The FIRST HALF of your cookie is %2$.*6$s\nTo verify your new address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$.*6$s?????\n(Replace the ????? with the SECOND HALF of the cookie, as sent to your NEW email address.)\nIf you did NOT request this change of email address, you do not need to do anything. Please contact the %1$s staff if you have questions." },
{ "NSEMAIL_EMAIL_VERIFY_SUBJECT", "Email address verification for %s" },
- { "NSEMAIL_EMAIL_VERIFY_BODY", "This email has been sent to verify that this address belongs to the same person as %5$s on %1$s. Your cookie is %2$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %1$s\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
+ { "NSEMAIL_EMAIL_VERIFY_BODY", "This email has been sent to verify that this address belongs to the same person as %5$s on %1$s. Your cookie is %2$s.\nTo verify your address as associated with this account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this email address to be associated with this account, you do not need to do anything. Please contact the %1$s staff if you have questions." },
{ "NSEMAIL_ALLOWAUTH_SUBJECT", "Authentication allowed for %s" },
- { "NSEMAIL_ALLOWAUTH_BODY", "This email has been sent to let you authenticate (auth) to account %5$s on %1$s. Your cookie is %2$s.\nTo auth to that account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %1$s\nIf you did NOT request this authorization, you do not need to do anything. Please contact the %1$s staff if you have questions." },
+ { "NSEMAIL_ALLOWAUTH_BODY", "This email has been sent to let you authenticate (auth) to account %5$s on %1$s. Your cookie is %2$s.\nTo auth to that account, log on to %1$s and type the following command:\n /msg %3$s@%4$s COOKIE %5$s %2$s\nIf you did NOT request this authorization, you do not need to do anything. Please contact the %1$s staff if you have questions." },
{ "CHECKPASS_YES", "Yes." },
{ "CHECKPASS_NO", "No." },
{ NULL, NULL }
};
static void nickserv_reclaim(struct userNode *user, struct nick_info *ni, enum reclaim_action action);
static void nickserv_reclaim_p(void *data);
+static int nickserv_addmask(struct userNode *user, struct handle_info *hi, const char *mask);
static struct {
unsigned int disable_nicks : 1;
unsigned long nochan_handle_expire_delay;
unsigned long modoper_level;
unsigned long set_epithet_level;
+ unsigned long set_title_level;
+ unsigned long set_fakehost_level;
unsigned long handles_per_email;
unsigned long email_search_level;
const char *network_name;
unsigned long auto_reclaim_delay;
unsigned char default_maxlogins;
unsigned char hard_maxlogins;
+ unsigned long ounregister_inactive;
+ unsigned long ounregister_flags;
} nickserv_conf;
/* We have 2^32 unique account IDs to use. */
unsigned long int highest_id = 0;
+#define WALK_NOTES(HANDLE, PREV, NOTE) \
+ for (PREV = NULL, NOTE = (HANDLE)->notes; NOTE != NULL; PREV = NOTE, NOTE = NOTE->next) \
+ if (NOTE->expires && NOTE->expires < now) { \
+ if (PREV) PREV->next = NOTE->next; else (HANDLE)->notes = NOTE->next; \
+ free(NOTE); \
+ if (!(NOTE = PREV ? PREV : (HANDLE)->notes)) break; \
+ } else
+
static char *
canonicalize_hostmask(char *mask)
{
char *out = mask, *temp;
if ((temp = strchr(mask, '!'))) {
- temp++;
- while (*temp) *out++ = *temp++;
- *out++ = 0;
+ temp++;
+ while (*temp) *out++ = *temp++;
+ *out++ = 0;
}
return mask;
}
id = 1 + highest_id++;
} else {
/* Note: highest_id is and must always be the highest ID. */
- if(id > highest_id) {
+ if (id > highest_id) {
highest_id = id;
}
}
hi = calloc(1, sizeof(*hi));
hi->userlist_style = HI_DEFAULT_STYLE;
- hi->announcements = '?';
hi->handle = strdup(handle);
safestrncpy(hi->passwd, passwd, sizeof(hi->passwd));
hi->infoline = NULL;
dict_insert(nickserv_nick_dict, ni->nick, ni);
}
-static void
-free_nick_info(void *vni)
-{
- struct nick_info *ni = vni;
- free(ni);
-}
-
static void
delete_nick(struct nick_info *ni)
{
}
/* Remove ni from the nick_info linked list. */
if (ni == ni->owner->nicks) {
- ni->owner->nicks = ni->next;
+ ni->owner->nicks = ni->next;
} else {
- last = ni->owner->nicks;
- next = last->next;
- while (next != ni) {
- last = next;
- next = last->next;
- }
- last->next = next->next;
+ last = ni->owner->nicks;
+ next = last->next;
+ while (next != ni) {
+ last = next;
+ next = last->next;
+ }
+ last->next = next->next;
}
dict_remove(nickserv_nick_dict, ni->nick);
}
reg_unreg_func(unreg_func_t func)
{
if (unreg_func_used == unreg_func_size) {
- if (unreg_func_size) {
- unreg_func_size <<= 1;
- unreg_func_list = realloc(unreg_func_list, unreg_func_size*sizeof(unreg_func_t));
- } else {
- unreg_func_size = 8;
- unreg_func_list = malloc(unreg_func_size*sizeof(unreg_func_t));
- }
+ if (unreg_func_size) {
+ unreg_func_size <<= 1;
+ unreg_func_list = realloc(unreg_func_list, unreg_func_size*sizeof(unreg_func_t));
+ } else {
+ unreg_func_size = 8;
+ unreg_func_list = malloc(unreg_func_size*sizeof(unreg_func_t));
+ }
}
unreg_func_list[unreg_func_used++] = func;
}
delete_nick(hi->nicks);
free(hi->infoline);
free(hi->epithet);
+ free(hi->fakehost);
if (hi->cookie) {
timeq_del(hi->cookie->expires, nickserv_free_cookie, hi->cookie, 0);
nickserv_free_cookie(hi->cookie);
}
+ while (hi->notes) {
+ struct handle_note *note = hi->notes;
+ hi->notes = note->next;
+ free(note);
+ }
if (hi->email_addr) {
struct handle_info_list *hil = dict_find(nickserv_email_dict, hi->email_addr, NULL);
handle_info_list_remove(hil, hi);
}
if (!IsOper(user) && (!IsHelping(user) || min_level)) {
- if (!quiet)
+ if (!quiet)
send_message(user, bot, "NSMSG_NO_ACCESS");
- return 0;
+ return 0;
}
if (HANDLE_FLAGGED(user->handle_info, OPER_SUSPENDED)) {
- if (!quiet)
+ if (!quiet)
send_message(user, bot, "MSG_OPER_SUSPENDED");
- return 0;
+ return 0;
}
if (user->handle_info->opserv_level < min_level) {
- if (!quiet)
+ if (!quiet)
send_message(user, bot, "NSMSG_NO_ACCESS");
- return 0;
+ return 0;
}
return 1;
return 0;
/* check against maximum length */
if (strlen(handle) > NICKSERV_HANDLE_LEN)
- return 0;
+ return 0;
/* for consistency, only allow account names that could be nicks */
if (!is_valid_nick(handle))
return 0;
return 0;
}
if (IsLocal(target)) {
- send_message(user, service, "NSMSG_USER_IS_SERVICE", target->nick);
+ if (IsService(target))
+ send_message(user, service, "NSMSG_USER_IS_SERVICE", target->nick);
+ else
+ send_message(user, service, "MSG_USER_AUTHENTICATE", target->nick);
return 0;
}
if (!(hi = target->handle_info)) {
if (!(hi = smart_get_handle_info(nickserv, user, target)))
return 0;
if (HANDLE_FLAGGED(user->handle_info, OPER_SUSPENDED)) {
- send_message(user, nickserv, "MSG_OPER_SUSPENDED");
- return 0;
+ send_message(user, nickserv, "MSG_OPER_SUSPENDED");
+ return 0;
}
return oper_outranks(user, hi) ? hi : NULL;
}
return 1;
/* If they are allowauthed to this account, allow it (removing the aa). */
if (dict_find(nickserv_allow_auth_dict, user->nick, NULL) == hi) {
- dict_remove(nickserv_allow_auth_dict, user->nick);
- return 2;
+ dict_remove(nickserv_allow_auth_dict, user->nick);
+ return 2;
}
/* The user is not allowed to use this account. */
return 0;
{
unsigned int i, len;
unsigned int cnt_digits = 0, cnt_upper = 0, cnt_lower = 0;
+ int p;
+
len = strlen(pass);
if (len < nickserv_conf.password_min_length) {
if (user)
send_message(user, nickserv, "NSMSG_PASSWORD_ACCOUNT");
return 0;
}
- dict_find(nickserv_conf.weak_password_dict, pass, &i);
- if (i) {
+ dict_find(nickserv_conf.weak_password_dict, pass, &p);
+ if (p) {
if (user)
send_message(user, nickserv, "NSMSG_PASSWORD_DICTIONARY");
return 0;
}
for (i=0; i<len; i++) {
- if (isdigit(pass[i]))
+ if (isdigit(pass[i]))
cnt_digits++;
- if (isupper(pass[i]))
+ if (isupper(pass[i]))
cnt_upper++;
- if (islower(pass[i]))
+ if (islower(pass[i]))
cnt_lower++;
}
if ((cnt_lower < nickserv_conf.password_min_lower)
- || (cnt_upper < nickserv_conf.password_min_upper)
- || (cnt_digits < nickserv_conf.password_min_digits)) {
+ || (cnt_upper < nickserv_conf.password_min_upper)
+ || (cnt_digits < nickserv_conf.password_min_digits)) {
if (user)
send_message(user, nickserv, "NSMSG_PASSWORD_READABLE", nickserv_conf.password_min_digits, nickserv_conf.password_min_upper, nickserv_conf.password_min_lower);
return 0;
reg_auth_func(auth_func_t func)
{
if (auth_func_used == auth_func_size) {
- if (auth_func_size) {
- auth_func_size <<= 1;
- auth_func_list = realloc(auth_func_list, auth_func_size*sizeof(auth_func_t));
- } else {
- auth_func_size = 8;
- auth_func_list = malloc(auth_func_size*sizeof(auth_func_t));
- }
+ if (auth_func_size) {
+ auth_func_size <<= 1;
+ auth_func_list = realloc(auth_func_list, auth_func_size*sizeof(auth_func_t));
+ } else {
+ auth_func_size = 8;
+ auth_func_list = malloc(auth_func_size*sizeof(auth_func_t));
+ }
}
auth_func_list[auth_func_used++] = func;
}
rf_list[rf_list_used++] = func;
}
+static char *
+generate_fakehost(struct handle_info *handle)
+{
+ extern const char *hidden_host_suffix;
+ static char buffer[HOSTLEN+1];
+
+ if (!handle->fakehost) {
+ snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix);
+ return buffer;
+ } else if (handle->fakehost[0] == '.') {
+ /* A leading dot indicates the stored value is actually a title. */
+ snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, nickserv_conf.titlehost_suffix);
+ return buffer;
+ }
+ return handle->fakehost;
+}
+
+static void
+apply_fakehost(struct handle_info *handle)
+{
+ struct userNode *target;
+ char *fake;
+
+ if (!handle->users)
+ return;
+ fake = generate_fakehost(handle);
+ for (target = handle->users; target; target = target->next_authed)
+ assign_fakehost(target, fake, 1);
+}
+
static void
set_user_handle_info(struct userNode *user, struct handle_info *hi, int stamp)
{
return;
if (user->handle_info) {
- struct userNode *other;
+ struct userNode *other;
- if (IsHelper(user))
+ if (IsHelper(user))
userList_remove(&curr_helpers, user);
- /* remove from next_authed linked list */
- if (user->handle_info->users == user) {
- user->handle_info->users = user->next_authed;
- } else {
- for (other = user->handle_info->users;
- other->next_authed != user;
- other = other->next_authed) ;
- other->next_authed = user->next_authed;
- }
+ /* remove from next_authed linked list */
+ if (user->handle_info->users == user) {
+ user->handle_info->users = user->next_authed;
+ } else {
+ for (other = user->handle_info->users;
+ other->next_authed != user;
+ other = other->next_authed) ;
+ other->next_authed = user->next_authed;
+ }
/* if nobody left on old handle, and they're not an oper, remove !god */
if (!user->handle_info->users && !user->handle_info->opserv_level)
HANDLE_CLEAR_FLAG(user->handle_info, HELPING);
/* record them as being last seen at this time */
- user->handle_info->lastseen = now;
+ user->handle_info->lastseen = now;
/* and record their hostmask */
snprintf(user->handle_info->last_quit_host, sizeof(user->handle_info->last_quit_host), "%s@%s", user->ident, user->hostname);
}
for (other = hi->users; other; other = other->next_authed)
send_message(other, nickserv, "NSMSG_CLONE_AUTH", user->nick, user->ident, user->hostname);
}
- user->next_authed = hi->users;
- hi->users = user;
- hi->lastseen = now;
- if (IsHelper(user))
+ user->next_authed = hi->users;
+ hi->users = user;
+ hi->lastseen = now;
+ if (IsHelper(user))
userList_append(&curr_helpers, user);
+ if (hi->fakehost || old_info)
+ apply_fakehost(hi);
+
if (stamp) {
#ifdef WITH_PROTOCOL_BAHAMUT
/* Stamp users with their account ID. */
timeq_del(0, nickserv_reclaim_p, user, TIMEQ_IGNORE_WHEN);
} else {
/* We cannot clear the user's account ID, unfortunately. */
- user->next_authed = NULL;
+ user->next_authed = NULL;
}
}
char crypted[MD5_CRYPT_LENGTH];
if ((hi = dict_find(nickserv_handle_dict, handle, NULL))) {
- send_message(user, nickserv, "NSMSG_HANDLE_EXISTS", handle);
- return 0;
+ send_message(user, nickserv, "NSMSG_HANDLE_EXISTS", handle);
+ return 0;
}
if (!is_secure_password(handle, passwd, user))
hi = register_handle(handle, crypted, 0);
hi->masks = alloc_string_list(1);
hi->users = NULL;
+ hi->language = lang_C;
hi->registered = now;
hi->lastseen = now;
hi->flags = HI_DEFAULT_FLAGS;
case ACTIVATION:
hi->passwd[0] = 0; /* invalidate password */
send_message(user, nickserv, "NSMSG_USE_COOKIE_REGISTER");
- fmt = user_find_message(user, "NSEMAIL_ACTIVATION_SUBJECT");
+ fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_SUBJECT");
snprintf(subject, sizeof(subject), fmt, netname);
- fmt = user_find_message(user, "NSEMAIL_ACTIVATION_BODY");
+ fmt = handle_find_message(hi, "NSEMAIL_ACTIVATION_BODY");
snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
first_time = 1;
break;
case PASSWORD_CHANGE:
send_message(user, nickserv, "NSMSG_USE_COOKIE_RESETPASS");
- fmt = user_find_message(user, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
+ fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_SUBJECT");
snprintf(subject, sizeof(subject), fmt, netname);
- fmt = user_find_message(user, "NSEMAIL_PASSWORD_CHANGE_BODY");
+ fmt = handle_find_message(hi, "NSEMAIL_PASSWORD_CHANGE_BODY");
snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
break;
case EMAIL_CHANGE:
hi->email_addr = cookie->data;
if (misc) {
send_message(user, nickserv, "NSMSG_USE_COOKIE_EMAIL_2");
- fmt = user_find_message(user, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
+ fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_SUBJECT");
snprintf(subject, sizeof(subject), fmt, netname);
- fmt = user_find_message(user, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
+ fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_NEW");
snprintf(body, sizeof(body), fmt, netname, cookie->cookie+COOKIELEN/2, nickserv->nick, self->name, hi->handle, COOKIELEN/2);
- sendmail(nickserv, hi, subject, body, 1);
- fmt = user_find_message(user, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
- snprintf(body, sizeof(body), fmt, netname, cookie->cookie+COOKIELEN/2, nickserv->nick, self->name, hi->handle, COOKIELEN/2, hi->email_addr);
+ mail_send(nickserv, hi, subject, body, 1);
+ fmt = handle_find_message(hi, "NSEMAIL_EMAIL_CHANGE_BODY_OLD");
+ snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle, COOKIELEN/2, hi->email_addr);
} else {
send_message(user, nickserv, "NSMSG_USE_COOKIE_EMAIL_1");
- fmt = user_find_message(user, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
+ fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_SUBJECT");
snprintf(subject, sizeof(subject), fmt, netname);
- fmt = user_find_message(user, "NSEMAIL_EMAIL_VERIFY_BODY");
+ fmt = handle_find_message(hi, "NSEMAIL_EMAIL_VERIFY_BODY");
snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
- sendmail(nickserv, hi, subject, body, 1);
+ mail_send(nickserv, hi, subject, body, 1);
subject[0] = 0;
}
hi->email_addr = misc;
break;
case ALLOWAUTH:
- fmt = user_find_message(user, "NSEMAIL_ALLOWAUTH_SUBJECT");
+ fmt = handle_find_message(hi, "NSEMAIL_ALLOWAUTH_SUBJECT");
snprintf(subject, sizeof(subject), fmt, netname);
- fmt = user_find_message(user, "NSEMAIL_ALLOWAUTH_BODY");
+ fmt = handle_find_message(hi, "NSEMAIL_ALLOWAUTH_BODY");
snprintf(body, sizeof(body), fmt, netname, cookie->cookie, nickserv->nick, self->name, hi->handle);
+ send_message(user, nickserv, "NSMSG_USE_COOKIE_AUTH");
break;
default:
log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d in nickserv_make_cookie.", cookie->type);
break;
}
if (subject[0])
- sendmail(nickserv, hi, subject, body, first_time);
+ mail_send(nickserv, hi, subject, body, first_time);
nickserv_bake_cookie(cookie);
}
static NICKSERV_FUNC(cmd_register)
{
+ irc_in_addr_t ip;
struct handle_info *hi;
const char *email_addr, *password;
int no_auth;
if (!IsOper(user) && !dict_size(nickserv_handle_dict)) {
- /* Require the first handle registered to belong to someone +o. */
- reply("NSMSG_REQUIRE_OPER");
- return 0;
+ /* Require the first handle registered to belong to someone +o. */
+ reply("NSMSG_REQUIRE_OPER");
+ return 0;
}
if (user->handle_info) {
return 0;
}
+ if (IsRegistering(user)) {
+ reply("NSMSG_ALREADY_REGISTERING");
+ return 0;
+ }
+
if (IsStamped(user)) {
/* Unauthenticated users might still have been stamped
previously and could therefore have a hidden host;
}
/* .. and that we are allowed to send to it. */
- if ((str = sendmail_prohibited_address(email_addr))) {
+ if ((str = mail_prohibited_address(email_addr))) {
reply("NSMSG_EMAIL_PROHIBITED", email_addr, str);
return 0;
}
string_list_append(hi->masks, strdup("*@*"));
} else {
string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
- if (user->ip.s_addr && user->hostname[strspn(user->hostname, "0123456789.")])
+ if (irc_in_addr_is_valid(user->ip) && !irc_pton(&ip, NULL, user->hostname))
string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
}
if (no_auth)
nickserv_make_cookie(user, hi, ACTIVATION, hi->passwd);
+ /* Set registering flag.. */
+ user->modes |= FLAGS_REGISTERING;
+
return 1;
}
struct userNode *settee;
struct handle_info *hi;
- NICKSERV_MIN_PARMS(4);
+ NICKSERV_MIN_PARMS(3);
if (!is_valid_handle(argv[1])) {
reply("NSMSG_BAD_HANDLE", argv[1]);
return 0;
}
- if (strchr(argv[3], '@')) {
- mask = canonicalize_hostmask(strdup(argv[3]));
- if (argc > 4) {
- settee = GetUserH(argv[4]);
- if (!settee) {
- reply("MSG_NICK_UNKNOWN", argv[4]);
+ if (argc < 4) {
+ mask = NULL;
+ settee = NULL;
+ } else if (strchr(argv[3], '@')) {
+ mask = canonicalize_hostmask(strdup(argv[3]));
+ if (argc > 4) {
+ settee = GetUserH(argv[4]);
+ if (!settee) {
+ reply("MSG_NICK_UNKNOWN", argv[4]);
free(mask);
- return 0;
- }
- } else {
- settee = NULL;
- }
+ return 0;
+ }
+ } else {
+ settee = NULL;
+ }
} else if ((settee = GetUserH(argv[3]))) {
- mask = generate_hostmask(settee, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
+ mask = generate_hostmask(settee, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
} else {
- reply("NSMSG_REGISTER_BAD_NICKMASK", argv[3]);
- return 0;
+ reply("NSMSG_REGISTER_BAD_NICKMASK", argv[3]);
+ return 0;
}
if (settee && settee->handle_info) {
reply("NSMSG_USER_PREV_AUTH", settee->nick);
free(mask);
return 0;
}
- string_list_append(hi->masks, mask);
+ if (mask)
+ string_list_append(hi->masks, mask);
return 1;
}
reply("NSMSG_HANDLEINFO_REGGED", ctime(&hi->registered));
if (!hi->users) {
- intervalString(buff, now - hi->lastseen);
- reply("NSMSG_HANDLEINFO_LASTSEEN", buff);
+ intervalString(buff, now - hi->lastseen, user->handle_info);
+ reply("NSMSG_HANDLEINFO_LASTSEEN", buff);
} else {
- reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
+ reply("NSMSG_HANDLEINFO_LASTSEEN_NOW");
}
reply("NSMSG_HANDLEINFO_INFOLINE", (hi->infoline ? hi->infoline : nsmsg_none));
struct do_not_register *dnr;
if ((dnr = chanserv_is_dnr(NULL, hi)))
reply("NSMSG_HANDLEINFO_DNR", dnr->setter, dnr->reason);
- if (!oper_outranks(user, hi))
+ if ((user->handle_info->opserv_level < 900) && !oper_outranks(user, hi))
return 1;
} else if (hi != user->handle_info)
return 1;
+ if (IsOper(user))
+ reply("NSMSG_HANDLEINFO_KARMA", hi->karma);
+
if (nickserv_conf.email_enabled)
reply("NSMSG_HANDLEINFO_EMAIL_ADDR", visible_email_addr(user, hi));
reply(type);
}
+ if (oper_has_access(user, cmd->parent->bot, 0, 1) || IsStaff(user)) {
+ if (!hi->notes) {
+ reply("NSMSG_HANDLEINFO_NO_NOTES");
+ } else {
+ struct handle_note *prev, *note;
+
+ WALK_NOTES(hi, prev, note) {
+ char set_time[INTERVALLEN];
+ intervalString(set_time, now - note->set, user->handle_info);
+ if (note->expires) {
+ char exp_time[INTERVALLEN];
+ intervalString(exp_time, note->expires - now, user->handle_info);
+ reply("NSMSG_HANDLEINFO_NOTE_EXPIRES", note->id, set_time, note->setter, exp_time, note->note);
+ } else {
+ reply("NSMSG_HANDLEINFO_NOTE", note->id, set_time, note->setter, note->note);
+ }
+ }
+ }
+ }
+
if (hi->flags) {
- unsigned long flen = 1;
- char flags[34]; /* 32 bits possible plus '+' and '\0' */
- flags[0] = '+';
- for (i=0, flen=1; handle_flags[i]; i++)
- if (hi->flags & 1 << i)
+ unsigned long flen = 1;
+ char flags[34]; /* 32 bits possible plus '+' and '\0' */
+ flags[0] = '+';
+ for (i=0, flen=1; handle_flags[i]; i++)
+ if (hi->flags & 1 << i)
flags[flen++] = handle_flags[i];
- flags[flen] = 0;
- reply("NSMSG_HANDLEINFO_FLAGS", flags);
+ flags[flen] = 0;
+ reply("NSMSG_HANDLEINFO_FLAGS", flags);
} else {
- reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none);
+ reply("NSMSG_HANDLEINFO_FLAGS", nsmsg_none);
}
if (HANDLE_FLAGGED(hi, SUPPORT_HELPER)
reply("NSMSG_HANDLEINFO_EPITHET", (hi->epithet ? hi->epithet : nsmsg_none));
}
+ if (hi->fakehost)
+ reply("NSMSG_HANDLEINFO_FAKEHOST", (hi->fakehost ? hi->fakehost : handle_find_message(hi, "MSG_NONE")));
+
if (hi->last_quit_host[0])
reply("NSMSG_HANDLEINFO_LAST_HOST", hi->last_quit_host);
else
reply("NSMSG_HANDLEINFO_LAST_HOST_UNKNOWN");
if (nickserv_conf.disable_nicks) {
- /* nicks disabled; don't show anything about registered nicks */
+ /* nicks disabled; don't show anything about registered nicks */
} else if (hi->nicks) {
- struct nick_info *ni, *next_ni;
- for (ni = hi->nicks; ni; ni = next_ni) {
- herelen = strlen(ni->nick);
- if (pos + herelen + 1 > ArrayLength(buff)) {
- next_ni = ni;
- goto print_nicks_buff;
- } else {
- next_ni = ni->next;
- }
- memcpy(buff+pos, ni->nick, herelen);
- pos += herelen; buff[pos++] = ' ';
- if (!next_ni) {
- print_nicks_buff:
- buff[pos-1] = 0;
- reply("NSMSG_HANDLEINFO_NICKS", buff);
- pos = 0;
- }
- }
+ struct nick_info *ni, *next_ni;
+ for (ni = hi->nicks; ni; ni = next_ni) {
+ herelen = strlen(ni->nick);
+ if (pos + herelen + 1 > ArrayLength(buff)) {
+ next_ni = ni;
+ goto print_nicks_buff;
+ } else {
+ next_ni = ni->next;
+ }
+ memcpy(buff+pos, ni->nick, herelen);
+ pos += herelen; buff[pos++] = ' ';
+ if (!next_ni) {
+ print_nicks_buff:
+ buff[pos-1] = 0;
+ reply("NSMSG_HANDLEINFO_NICKS", buff);
+ pos = 0;
+ }
+ }
} else {
- reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none);
+ reply("NSMSG_HANDLEINFO_NICKS", nsmsg_none);
}
if (hi->masks->used) {
}
if (hi->channels) {
- struct userData *channel, *next;
- char *name;
+ struct userData *channel, *next;
+ char *name;
- for (channel = hi->channels; channel; channel = next) {
- next = channel->u_next;
+ for (channel = hi->channels; channel; channel = next) {
+ next = channel->u_next;
name = channel->channel->channel->name;
- herelen = strlen(name);
- if (pos + herelen + 7 > ArrayLength(buff)) {
- next = channel;
+ herelen = strlen(name);
+ if (pos + herelen + 7 > ArrayLength(buff)) {
+ next = channel;
goto print_chans_buff;
- }
+ }
if (IsUserSuspended(channel))
buff[pos++] = '-';
pos += sprintf(buff+pos, "%d:%s ", channel->access, name);
- if (next == NULL) {
- print_chans_buff:
- buff[pos-1] = 0;
- reply("NSMSG_HANDLEINFO_CHANNELS", buff);
- pos = 0;
- }
- }
+ if (next == NULL) {
+ print_chans_buff:
+ buff[pos-1] = 0;
+ reply("NSMSG_HANDLEINFO_CHANNELS", buff);
+ pos = 0;
+ }
+ }
} else {
- reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none);
+ reply("NSMSG_HANDLEINFO_CHANNELS", nsmsg_none);
}
for (target = hi->users; target; target = next_un) {
- herelen = strlen(target->nick);
- if (pos + herelen + 1 > ArrayLength(buff)) {
- next_un = target;
- goto print_cnick_buff;
- } else {
- next_un = target->next_authed;
- }
- memcpy(buff+pos, target->nick, herelen);
- pos += herelen; buff[pos++] = ' ';
- if (!next_un) {
- print_cnick_buff:
- buff[pos-1] = 0;
- reply("NSMSG_HANDLEINFO_CURRENT", buff);
- pos = 0;
- }
+ herelen = strlen(target->nick);
+ if (pos + herelen + 1 > ArrayLength(buff)) {
+ next_un = target;
+ goto print_cnick_buff;
+ } else {
+ next_un = target->next_authed;
+ }
+ memcpy(buff+pos, target->nick, herelen);
+ pos += herelen; buff[pos++] = ' ';
+ if (!next_un) {
+ print_cnick_buff:
+ buff[pos-1] = 0;
+ reply("NSMSG_HANDLEINFO_CURRENT", buff);
+ pos = 0;
+ }
}
return 1;
NICKSERV_MIN_PARMS(2);
if (!(target = GetUserH(argv[1]))) {
- reply("MSG_NICK_UNKNOWN", argv[1]);
- return 0;
+ reply("MSG_NICK_UNKNOWN", argv[1]);
+ return 0;
}
if (target->handle_info)
- reply("NSMSG_USERINFO_AUTHED_AS", target->nick, target->handle_info->handle);
+ reply("NSMSG_USERINFO_AUTHED_AS", target->nick, target->handle_info->handle);
else
- reply("NSMSG_USERINFO_NOT_AUTHED", target->nick);
+ reply("NSMSG_USERINFO_NOT_AUTHED", target->nick);
return 1;
}
NICKSERV_MIN_PARMS(2);
if (!(ni = get_nick_info(argv[1]))) {
- reply("MSG_NICK_UNKNOWN", argv[1]);
- return 0;
+ reply("MSG_NICK_UNKNOWN", argv[1]);
+ return 0;
}
reply("NSMSG_NICKINFO_OWNER", ni->nick, ni->owner->handle);
return 1;
}
+static NICKSERV_FUNC(cmd_notes)
+{
+ struct handle_info *hi;
+ struct handle_note *prev, *note;
+ unsigned int hits;
+
+ NICKSERV_MIN_PARMS(2);
+ if (!(hi = get_victim_oper(user, argv[1])))
+ return 0;
+ hits = 0;
+ WALK_NOTES(hi, prev, note) {
+ char set_time[INTERVALLEN];
+ intervalString(set_time, now - note->set, user->handle_info);
+ if (note->expires) {
+ char exp_time[INTERVALLEN];
+ intervalString(exp_time, note->expires - now, user->handle_info);
+ reply("NSMSG_NOTE_EXPIRES", note->id, set_time, note->setter, exp_time, note->note);
+ } else {
+ reply("NSMSG_NOTE", note->id, set_time, note->setter, note->note);
+ }
+ ++hits;
+ }
+ reply("NSMSG_NOTE_COUNT", hits, argv[1]);
+ return 1;
+}
+
static NICKSERV_FUNC(cmd_rename_handle)
{
struct handle_info *hi;
reply("NSMSG_HANDLE_NOT_FOUND");
return 0;
}
+ /* Responses from here on look up the language used by the handle they asked about. */
passwd = argv[pw_arg];
if (!valid_user_for(user, hi)) {
if (hi->email_addr && nickserv_conf.email_enabled)
- reply("NSMSG_USE_AUTHCOOKIE", hi->handle, hi->handle);
+ send_message_type(4, user, cmd->parent->bot,
+ handle_find_message(hi, "NSMSG_USE_AUTHCOOKIE"),
+ hi->handle);
else
- reply("NSMSG_HOSTMASK_INVALID", hi->handle);
+ send_message_type(4, user, cmd->parent->bot,
+ handle_find_message(hi, "NSMSG_HOSTMASK_INVALID"),
+ hi->handle);
argv[pw_arg] = "BADMASK";
return 1;
}
if (!checkpass(passwd, hi->passwd)) {
unsigned int n;
- reply("NSMSG_PASSWORD_INVALID");
+ send_message_type(4, user, cmd->parent->bot,
+ handle_find_message(hi, "NSMSG_PASSWORD_INVALID"));
argv[pw_arg] = "BADPASS";
for (n=0; n<failpw_func_used; n++) failpw_func_list[n](user, hi);
if (nickserv_conf.autogag_enabled) {
return 1;
}
if (HANDLE_FLAGGED(hi, SUSPENDED)) {
- reply("NSMSG_HANDLE_SUSPENDED");
+ send_message_type(4, user, cmd->parent->bot,
+ handle_find_message(hi, "NSMSG_HANDLE_SUSPENDED"));
argv[pw_arg] = "SUSPENDED";
return 1;
}
maxlogins = hi->maxlogins ? hi->maxlogins : nickserv_conf.default_maxlogins;
for (used = 0, other = hi->users; other; other = other->next_authed) {
if (++used >= maxlogins) {
- reply("NSMSG_MAX_LOGINS", maxlogins);
+ send_message_type(4, user, cmd->parent->bot,
+ handle_find_message(hi, "NSMSG_MAX_LOGINS"),
+ maxlogins);
argv[pw_arg] = "MAXLOGINS";
return 1;
}
}
+ set_user_handle_info(user, hi, 1);
if (nickserv_conf.email_required && !hi->email_addr)
reply("NSMSG_PLEASE_SET_EMAIL");
if (!is_secure_password(hi->handle, passwd, NULL))
reply("NSMSG_WEAK_PASSWORD");
if (hi->passwd[0] != '$')
cryptpass(passwd, hi->passwd);
-
- reply("NSMSG_AUTH_SUCCESS");
+ if (!hi->masks->used) {
+ irc_in_addr_t ip;
+ string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
+ if (irc_in_addr_is_valid(user->ip) && irc_pton(&ip, NULL, user->hostname))
+ string_list_append(hi->masks, generate_hostmask(user, GENMASK_OMITNICK|GENMASK_BYIP|GENMASK_NO_HIDING|GENMASK_ANY_IDENT));
+ }
argv[pw_arg] = "****";
- set_user_handle_info(user, hi, 1);
+ reply("NSMSG_AUTH_SUCCESS");
return 1;
}
/* Unauthenticated users might still have been stamped
previously and could therefore have a hidden host;
do not allow them to authenticate to an account. */
- send_message(target, nickserv, "NSMSG_USER_PREV_STAMP", target->nick);
+ reply("NSMSG_USER_PREV_STAMP", target->nick);
return 0;
}
if (argc == 2)
return 0;
}
nickserv_make_cookie(user, hi, ALLOWAUTH, NULL);
- reply("NSMSG_USE_COOKIE_AUTH");
return 1;
}
nickserv_set_email_addr(hi, hi->cookie->data);
reply("NSMSG_EMAIL_CHANGED");
break;
- case ALLOWAUTH:
+ case ALLOWAUTH: {
+ char *mask = generate_hostmask(user, GENMASK_OMITNICK|GENMASK_NO_HIDING|GENMASK_ANY_IDENT);
set_user_handle_info(user, hi, 1);
+ nickserv_addmask(user, hi, mask);
reply("NSMSG_AUTH_SUCCESS");
+ free(mask);
break;
+ }
default:
reply("NSMSG_BAD_COOKIE_TYPE", hi->cookie->type);
log_module(NS_LOG, LOG_ERROR, "Bad cookie type %d for account %s.", hi->cookie->type, hi->handle);
}
ni = dict_find(nickserv_nick_dict, nick, NULL);
if (ni) {
- reply("NSMSG_NICK_EXISTS", nick);
- return 0;
+ reply("NSMSG_NICK_EXISTS", nick);
+ return 0;
}
register_nick(nick, target);
reply("NSMSG_OREGNICK_SUCCESS", nick, target->handle);
}
ni = dict_find(nickserv_nick_dict, user->nick, NULL);
if (ni) {
- reply("NSMSG_NICK_EXISTS", user->nick);
- return 0;
+ reply("NSMSG_NICK_EXISTS", user->nick);
+ return 0;
}
register_nick(user->nick, user->handle_info);
reply("NSMSG_REGNICK_SUCCESS", user->nick);
if (!is_secure_password(hi->handle, new_pass, user)) return 0;
if (!checkpass(old_pass, hi->passwd)) {
argv[1] = "BADPASS";
- reply("NSMSG_PASSWORD_INVALID");
- return 0;
+ reply("NSMSG_PASSWORD_INVALID");
+ return 0;
}
cryptpass(new_pass, hi->passwd);
argv[1] = "****";
}
static int
-nickserv_delmask(struct userNode *user, struct handle_info *hi, const char *del_mask)
+nickserv_delmask(struct userNode *user, struct handle_info *hi, const char *del_mask, int force)
{
unsigned int i;
for (i=0; i<hi->masks->used; i++) {
- if (!strcmp(del_mask, hi->masks->list[i])) {
- char *old_mask = hi->masks->list[i];
- if (hi->masks->used == 1) {
- send_message(user, nickserv, "NSMSG_DELMASK_NOTLAST");
- return 0;
- }
- hi->masks->list[i] = hi->masks->list[--hi->masks->used];
- send_message(user, nickserv, "NSMSG_DELMASK_SUCCESS", old_mask);
- free(old_mask);
- return 1;
- }
+ if (!strcmp(del_mask, hi->masks->list[i])) {
+ char *old_mask = hi->masks->list[i];
+ if (hi->masks->used == 1 && !force) {
+ send_message(user, nickserv, "NSMSG_DELMASK_NOTLAST");
+ return 0;
+ }
+ hi->masks->list[i] = hi->masks->list[--hi->masks->used];
+ send_message(user, nickserv, "NSMSG_DELMASK_SUCCESS", old_mask);
+ free(old_mask);
+ return 1;
+ }
}
send_message(user, nickserv, "NSMSG_DELMASK_NOT_FOUND");
return 0;
static NICKSERV_FUNC(cmd_delmask)
{
NICKSERV_MIN_PARMS(2);
- return nickserv_delmask(user, user->handle_info, argv[1]);
+ return nickserv_delmask(user, user->handle_info, argv[1], 0);
}
static NICKSERV_FUNC(cmd_odelmask)
NICKSERV_MIN_PARMS(3);
if (!(hi = get_victim_oper(user, argv[1])))
return 0;
- return nickserv_delmask(user, hi, argv[2]);
+ return nickserv_delmask(user, hi, argv[2], 1);
}
int
unsigned long added, removed, flag;
for (added=removed=nn=0; str[nn]; nn++) {
- switch (str[nn]) {
- case '+': add = 1; break;
- case '-': add = 0; break;
- default:
- if (!(pos = handle_inverse_flags[(unsigned char)str[nn]])) {
- send_message(user, bot, "NSMSG_INVALID_FLAG", str[nn]);
- return 0;
- }
+ switch (str[nn]) {
+ case '+': add = 1; break;
+ case '-': add = 0; break;
+ default:
+ if (!(pos = handle_inverse_flags[(unsigned char)str[nn]])) {
+ send_message(user, bot, "NSMSG_INVALID_FLAG", str[nn]);
+ return 0;
+ }
if (user && (user->handle_info->opserv_level < flag_access_levels[pos-1])) {
/* cheesy avoidance of looking up the flag name.. */
send_message(user, bot, "NSMSG_FLAG_PRIVILEGED", str[nn]);
return 0;
}
flag = 1 << (pos - 1);
- if (add)
+ if (add)
added |= flag, removed &= ~flag;
- else
+ else
removed |= flag, added &= ~flag;
- break;
- }
+ break;
+ }
}
*padded = added;
*premoved = removed;
unsigned int i;
char *set_display[] = {
"INFO", "WIDTH", "TABLEWIDTH", "COLOR", "PRIVMSG", "STYLE",
- "EMAIL", "ANNOUNCEMENTS", "MAXLOGINS"
+ "EMAIL", "MAXLOGINS", "LANGUAGE"
};
send_message(user, nickserv, "NSMSG_SETTING_LIST");
/* Do this so options are presented in a consistent order. */
for (i = 0; i < ArrayLength(set_display); ++i)
- if ((opt = dict_find(nickserv_opt_dict, set_display[i], NULL)))
- opt(user, hi, override, 0, NULL);
+ if ((opt = dict_find(nickserv_opt_dict, set_display[i], NULL)))
+ opt(user, hi, override, 0, NULL);
}
static NICKSERV_FUNC(cmd_set)
hi = user->handle_info;
if (argc < 2) {
- set_list(user, hi, 0);
- return 1;
+ set_list(user, hi, 0);
+ return 1;
}
if (!(opt = dict_find(nickserv_opt_dict, argv[1], NULL))) {
- reply("NSMSG_INVALID_OPTION", argv[1]);
+ reply("NSMSG_INVALID_OPTION", argv[1]);
return 0;
}
return opt(user, hi, 0, argc-1, argv+1);
static NICKSERV_FUNC(cmd_oset)
{
struct handle_info *hi;
+ struct svccmd *subcmd;
option_func_t *opt;
+ char cmdname[MAXLEN];
NICKSERV_MIN_PARMS(2);
return 0;
if (argc < 3) {
- set_list(user, hi, 0);
- return 1;
+ set_list(user, hi, 0);
+ return 1;
}
if (!(opt = dict_find(nickserv_opt_dict, argv[2], NULL))) {
- reply("NSMSG_INVALID_OPTION", argv[2]);
+ reply("NSMSG_INVALID_OPTION", argv[2]);
return 0;
}
+ sprintf(cmdname, "%s %s", cmd->name, argv[2]);
+ subcmd = dict_find(cmd->parent->commands, cmdname, NULL);
+ if (subcmd && !svccmd_can_invoke(user, cmd->parent->bot, subcmd, NULL, SVCCMD_NOISY))
+ return 0;
+
return opt(user, hi, 1, argc-2, argv+2);
}
{
const char *info;
if (argc > 1) {
- if ((argv[1][0] == '*') && (argv[1][1] == 0)) {
+ if ((argv[1][0] == '*') && (argv[1][1] == 0)) {
free(hi->infoline);
hi->infoline = NULL;
- } else {
- hi->infoline = strdup(unsplit_string(argv+1, argc-1, NULL));
- }
+ } else {
+ hi->infoline = strdup(unsplit_string(argv+1, argc-1, NULL));
+ }
}
info = hi->infoline ? hi->infoline : user_find_message(user, "MSG_NONE");
static OPTION_FUNC(opt_width)
{
- if (argc > 1) {
- unsigned int new_width = strtoul(argv[1], NULL, 0);
- hi->screen_width = new_width;
- }
+ if (argc > 1)
+ hi->screen_width = strtoul(argv[1], NULL, 0);
if ((hi->screen_width > 0) && (hi->screen_width < MIN_LINE_SIZE))
hi->screen_width = MIN_LINE_SIZE;
static OPTION_FUNC(opt_tablewidth)
{
- if (argc > 1) {
- unsigned int new_width = strtoul(argv[1], NULL, 0);
- hi->table_width = new_width;
- }
+ if (argc > 1)
+ hi->table_width = strtoul(argv[1], NULL, 0);
if ((hi->table_width > 0) && (hi->table_width < MIN_LINE_SIZE))
hi->table_width = MIN_LINE_SIZE;
static OPTION_FUNC(opt_color)
{
if (argc > 1) {
- if (enabled_string(argv[1]))
- HANDLE_SET_FLAG(hi, MIRC_COLOR);
+ if (enabled_string(argv[1]))
+ HANDLE_SET_FLAG(hi, MIRC_COLOR);
else if (disabled_string(argv[1]))
- HANDLE_CLEAR_FLAG(hi, MIRC_COLOR);
- else {
- send_message(user, nickserv, "MSG_INVALID_BINARY", argv[1]);
- return 0;
- }
+ HANDLE_CLEAR_FLAG(hi, MIRC_COLOR);
+ else {
+ send_message(user, nickserv, "MSG_INVALID_BINARY", argv[1]);
+ return 0;
+ }
}
send_message(user, nickserv, "NSMSG_SET_COLOR", user_find_message(user, HANDLE_FLAGGED(hi, MIRC_COLOR) ? "MSG_ON" : "MSG_OFF"));
static OPTION_FUNC(opt_privmsg)
{
if (argc > 1) {
- if (enabled_string(argv[1]))
- HANDLE_SET_FLAG(hi, USE_PRIVMSG);
+ if (enabled_string(argv[1]))
+ HANDLE_SET_FLAG(hi, USE_PRIVMSG);
else if (disabled_string(argv[1]))
- HANDLE_CLEAR_FLAG(hi, USE_PRIVMSG);
- else {
- send_message(user, nickserv, "MSG_INVALID_BINARY", argv[1]);
- return 0;
- }
+ HANDLE_CLEAR_FLAG(hi, USE_PRIVMSG);
+ else {
+ send_message(user, nickserv, "MSG_INVALID_BINARY", argv[1]);
+ return 0;
+ }
}
send_message(user, nickserv, "NSMSG_SET_PRIVMSG", user_find_message(user, HANDLE_FLAGGED(hi, USE_PRIVMSG) ? "MSG_ON" : "MSG_OFF"));
char *style;
if (argc > 1) {
- if (!irccasecmp(argv[1], "Zoot"))
- hi->userlist_style = HI_STYLE_ZOOT;
- else if (!irccasecmp(argv[1], "def"))
- hi->userlist_style = HI_STYLE_DEF;
+ if (!irccasecmp(argv[1], "Zoot"))
+ hi->userlist_style = HI_STYLE_ZOOT;
+ else if (!irccasecmp(argv[1], "def"))
+ hi->userlist_style = HI_STYLE_DEF;
}
switch (hi->userlist_style) {
case HI_STYLE_DEF:
- style = "def";
- break;
+ style = "def";
+ break;
case HI_STYLE_ZOOT:
default:
- style = "Zoot";
+ style = "Zoot";
}
send_message(user, nickserv, "NSMSG_SET_STYLE", style);
return 1;
}
-static OPTION_FUNC(opt_announcements)
-{
- const char *choice;
-
- if (argc > 1) {
- if (enabled_string(argv[1]))
- hi->announcements = 'y';
- else if (disabled_string(argv[1]))
- hi->announcements = 'n';
- else if (!strcmp(argv[1], "?") || !irccasecmp(argv[1], "default"))
- hi->announcements = '?';
- else {
- send_message(user, nickserv, "NSMSG_INVALID_ANNOUNCE", argv[1]);
- return 0;
- }
- }
-
- switch (hi->announcements) {
- case 'y': choice = user_find_message(user, "MSG_ON"); break;
- case 'n': choice = user_find_message(user, "MSG_OFF"); break;
- case '?': choice = "default"; break;
- default: choice = "unknown"; break;
- }
- send_message(user, nickserv, "NSMSG_SET_ANNOUNCEMENTS", choice);
- return 1;
-}
-
static OPTION_FUNC(opt_password)
{
if (!override) {
- send_message(user, nickserv, "NSMSG_USE_CMD_PASS");
- return 0;
+ send_message(user, nickserv, "NSMSG_USE_CMD_PASS");
+ return 0;
}
if (argc > 1)
- cryptpass(argv[1], hi->passwd);
+ cryptpass(argv[1], hi->passwd);
send_message(user, nickserv, "NSMSG_SET_PASSWORD", "***");
return 1;
unsigned int ii, flen;
if (!override) {
- send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
- return 0;
+ send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+ return 0;
}
if (argc > 1)
- nickserv_apply_flags(user, hi, argv[1]);
+ nickserv_apply_flags(user, hi, argv[1]);
for (ii = flen = 0; handle_flags[ii]; ii++)
if (hi->flags & (1 << ii))
send_message(user, nickserv, "NSMSG_BAD_EMAIL_ADDR");
return 0;
}
- if ((str = sendmail_prohibited_address(argv[1]))) {
+ if ((str = mail_prohibited_address(argv[1]))) {
send_message(user, nickserv, "NSMSG_EMAIL_PROHIBITED", argv[1], str);
return 0;
}
static OPTION_FUNC(opt_maxlogins)
{
- char maxlogins;
+ unsigned char maxlogins;
if (argc > 1) {
maxlogins = strtoul(argv[1], NULL, 0);
if ((maxlogins > nickserv_conf.hard_maxlogins) && !override) {
return 1;
}
+static OPTION_FUNC(opt_karma)
+{
+ if (!override) {
+ send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+ return 0;
+ }
+
+ if (argc > 1) {
+ if (argv[1][0] == '+' && isdigit(argv[1][1])) {
+ hi->karma += strtoul(argv[1] + 1, NULL, 10);
+ } else if (argv[1][0] == '-' && isdigit(argv[1][1])) {
+ hi->karma -= strtoul(argv[1] + 1, NULL, 10);
+ } else {
+ send_message(user, nickserv, "NSMSG_INVALID_KARMA", argv[1]);
+ }
+ }
+
+ send_message(user, nickserv, "NSMSG_SET_KARMA", hi->karma);
+ return 1;
+}
+
int
oper_try_set_access(struct userNode *user, struct userNode *bot, struct handle_info *target, unsigned int new_level) {
if (!oper_has_access(user, bot, nickserv_conf.modoper_level, 0))
int res;
if (!override) {
- send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
- return 0;
+ send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+ return 0;
}
res = (argc > 1) ? oper_try_set_access(user, nickserv, hi, strtoul(argv[1], NULL, 0)) : 0;
return 1;
}
+static OPTION_FUNC(opt_title)
+{
+ const char *title;
+
+ if (!override) {
+ send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+ return 0;
+ }
+
+ if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_title_level, 0)) {
+ title = argv[1];
+ if (strchr(title, '.')) {
+ send_message(user, nickserv, "NSMSG_TITLE_INVALID");
+ return 0;
+ }
+ if ((strlen(user->handle_info->handle) + strlen(title) +
+ strlen(nickserv_conf.titlehost_suffix) + 2) > HOSTLEN) {
+ send_message(user, nickserv, "NSMSG_TITLE_TRUNCATED");
+ return 0;
+ }
+
+ free(hi->fakehost);
+ if (!strcmp(title, "*")) {
+ hi->fakehost = NULL;
+ } else {
+ hi->fakehost = malloc(strlen(title)+2);
+ hi->fakehost[0] = '.';
+ strcpy(hi->fakehost+1, title);
+ }
+ apply_fakehost(hi);
+ } else if (hi->fakehost && (hi->fakehost[0] == '.'))
+ title = hi->fakehost + 1;
+ else
+ title = NULL;
+ if (!title)
+ title = user_find_message(user, "MSG_NONE");
+ send_message(user, nickserv, "NSMSG_SET_TITLE", title);
+ return 1;
+}
+
+static OPTION_FUNC(opt_fakehost)
+{
+ const char *fake;
+
+ if (!override) {
+ send_message(user, nickserv, "MSG_SETTING_PRIVILEGED", argv[0]);
+ return 0;
+ }
+
+ if ((argc > 1) && oper_has_access(user, nickserv, nickserv_conf.set_fakehost_level, 0)) {
+ fake = argv[1];
+ if ((strlen(fake) > HOSTLEN) || (fake[0] == '.')) {
+ send_message(user, nickserv, "NSMSG_FAKEHOST_INVALID", HOSTLEN);
+ return 0;
+ }
+ free(hi->fakehost);
+ if (!strcmp(fake, "*"))
+ hi->fakehost = NULL;
+ else
+ hi->fakehost = strdup(fake);
+ fake = hi->fakehost;
+ apply_fakehost(hi);
+ } else
+ fake = generate_fakehost(hi);
+ if (!fake)
+ fake = user_find_message(user, "MSG_NONE");
+ send_message(user, nickserv, "NSMSG_SET_FAKEHOST", fake);
+ return 1;
+}
+
static NICKSERV_FUNC(cmd_reclaim)
{
struct handle_info *hi;
nick = (argc < 2) ? user->nick : (const char*)argv[1];
ni = dict_find(nickserv_nick_dict, nick, NULL);
if (!ni) {
- reply("NSMSG_UNKNOWN_NICK", nick);
- return 0;
+ reply("NSMSG_UNKNOWN_NICK", nick);
+ return 0;
}
if (hi != ni->owner) {
- reply("NSMSG_NOT_YOUR_NICK", nick);
- return 0;
+ reply("NSMSG_NOT_YOUR_NICK", nick);
+ return 0;
}
reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
delete_nick(ni);
NICKSERV_MIN_PARMS(2);
if (!(ni = get_nick_info(argv[1]))) {
- reply("NSMSG_NICK_NOT_REGISTERED", argv[1]);
- return 0;
- }
- if (ni->owner->opserv_level >= user->handle_info->opserv_level) {
- reply("MSG_USER_OUTRANKED", ni->nick);
- return 0;
+ reply("NSMSG_NICK_NOT_REGISTERED", argv[1]);
+ return 0;
}
+ if (!oper_outranks(user, ni->owner))
+ return 0;
reply("NSMSG_UNREGNICK_SUCCESS", ni->nick);
delete_nick(ni);
return 1;
nickserv_unregister_handle(hi, user);
return 1;
} else {
- log_module(NS_LOG, LOG_INFO, "Account '%s' tried to unregister with the wrong password.", hi->handle);
- reply("NSMSG_PASSWORD_INVALID");
+ log_module(NS_LOG, LOG_INFO, "Account '%s' tried to unregister with the wrong password.", hi->handle);
+ reply("NSMSG_PASSWORD_INVALID");
return 0;
}
}
static NICKSERV_FUNC(cmd_ounregister)
{
struct handle_info *hi;
+ char reason[MAXLEN];
+ int force;
NICKSERV_MIN_PARMS(2);
if (!(hi = get_victim_oper(user, argv[1])))
return 0;
+
+ if (HANDLE_FLAGGED(hi, NODELETE)) {
+ reply("NSMSG_UNREGISTER_NODELETE", hi->handle);
+ return 0;
+ }
+
+ force = IsOper(user) && (argc > 2) && !irccasecmp(argv[2], "force");
+ if (!force &&
+ ((hi->flags & nickserv_conf.ounregister_flags)
+ || hi->users
+ || (hi->last_quit_host[0] && ((unsigned)(now - hi->lastseen) < nickserv_conf.ounregister_inactive)))) {
+ reply((IsOper(user) ? "NSMSG_UNREGISTER_MUST_FORCE" : "NSMSG_UNREGISTER_CANNOT_FORCE"), hi->handle);
+ return 0;
+ }
+
+ snprintf(reason, sizeof(reason), "%s unregistered account %s.", user->handle_info->handle, hi->handle);
+ global_message(MESSAGE_RECIPIENT_STAFF, reason);
nickserv_unregister_handle(hi, user);
- return 0;
+ return 1;
}
static NICKSERV_FUNC(cmd_status)
return 1;
}
+static NICKSERV_FUNC(cmd_addnote)
+{
+ struct handle_info *hi;
+ unsigned long duration;
+ char text[MAXLEN];
+ unsigned int id;
+ struct handle_note *prev;
+ struct handle_note *note;
+
+ /* Parse parameters and figure out values for note's fields. */
+ NICKSERV_MIN_PARMS(4);
+ hi = get_victim_oper(user, argv[1]);
+ if (!hi)
+ return 0;
+ if(!strcmp(argv[2], "0"))
+ duration = 0;
+ else if(!(duration = ParseInterval(argv[2])))
+ {
+ reply("MSG_INVALID_DURATION", argv[2]);
+ return 0;
+ }
+ if (duration > 2*365*86400) {
+ reply("NSMSG_EXCESSIVE_DURATION", argv[2]);
+ return 0;
+ }
+ unsplit_string(argv + 3, argc - 3, text);
+ WALK_NOTES(hi, prev, note) {}
+ id = prev ? (prev->id + 1) : 1;
+
+ /* Create the new note structure. */
+ note = calloc(1, sizeof(*note) + strlen(text));
+ note->next = NULL;
+ note->expires = duration ? (now + duration) : 0;
+ note->set = now;
+ note->id = id;
+ safestrncpy(note->setter, user->handle_info->handle, sizeof(note->setter));
+ strcpy(note->note, text);
+ if (prev)
+ prev->next = note;
+ else
+ hi->notes = note;
+ reply("NSMSG_NOTE_ADDED", id, hi->handle);
+ return 1;
+}
+
+static NICKSERV_FUNC(cmd_delnote)
+{
+ struct handle_info *hi;
+ struct handle_note *prev;
+ struct handle_note *note;
+ int id;
+
+ NICKSERV_MIN_PARMS(3);
+ hi = get_victim_oper(user, argv[1]);
+ if (!hi)
+ return 0;
+ id = strtoul(argv[2], NULL, 10);
+ WALK_NOTES(hi, prev, note) {
+ if (id == note->id) {
+ if (prev)
+ prev->next = note->next;
+ else
+ hi->notes = note->next;
+ free(note);
+ reply("NSMSG_NOTE_REMOVED", id, hi->handle);
+ return 1;
+ }
+ }
+ reply("NSMSG_NO_SUCH_NOTE", hi->handle, id);
+ return 0;
+}
+
static int
nickserv_saxdb_write(struct saxdb_context *ctx) {
dict_iterator_t it;
assert(hi->id);
#endif
saxdb_start_record(ctx, iter_key(it), 0);
- if (hi->announcements != '?') {
- flags[0] = hi->announcements;
- flags[1] = 0;
- saxdb_write_string(ctx, KEY_ANNOUNCEMENTS, flags);
- }
if (hi->cookie) {
struct handle_cookie *cookie = hi->cookie;
char *type;
saxdb_end_record(ctx);
}
}
+ if (hi->notes) {
+ struct handle_note *prev, *note;
+ saxdb_start_record(ctx, KEY_NOTES, 0);
+ WALK_NOTES(hi, prev, note) {
+ snprintf(flags, sizeof(flags), "%d", note->id);
+ saxdb_start_record(ctx, flags, 0);
+ if (note->expires)
+ saxdb_write_int(ctx, KEY_NOTE_EXPIRES, note->expires);
+ saxdb_write_int(ctx, KEY_NOTE_SET, note->set);
+ saxdb_write_string(ctx, KEY_NOTE_SETTER, note->setter);
+ saxdb_write_string(ctx, KEY_NOTE_NOTE, note->note);
+ saxdb_end_record(ctx);
+ }
+ saxdb_end_record(ctx);
+ }
if (hi->email_addr)
saxdb_write_string(ctx, KEY_EMAIL_ADDR, hi->email_addr);
if (hi->epithet)
saxdb_write_string(ctx, KEY_EPITHET, hi->epithet);
+ if (hi->fakehost)
+ saxdb_write_string(ctx, KEY_FAKEHOST, hi->fakehost);
if (hi->flags) {
int ii, flen;
if (hi->last_quit_host[0])
saxdb_write_string(ctx, KEY_LAST_QUIT_HOST, hi->last_quit_host);
saxdb_write_int(ctx, KEY_LAST_SEEN, hi->lastseen);
+ if (hi->karma != 0)
+ saxdb_write_sint(ctx, KEY_KARMA, hi->karma);
if (hi->masks->used)
saxdb_write_string_list(ctx, KEY_MASKS, hi->masks);
if (hi->maxlogins)
}
if (hi->opserv_level)
saxdb_write_int(ctx, KEY_OPSERV_LEVEL, hi->opserv_level);
- if (hi->language && (hi->language != lang_C))
+ if (hi->language != lang_C)
saxdb_write_string(ctx, KEY_LANGUAGE, hi->language->name);
saxdb_write_string(ctx, KEY_PASSWD, hi->passwd);
saxdb_write_int(ctx, KEY_REGISTER_ON, hi->registered);
for (cList2=hi_to->channels; cList2; cList2=cList2->u_next)
if (cList->channel == cList2->channel)
break;
- log_module(NS_LOG, LOG_DEBUG, "Merging %s->%s@%s: before %p->%p->%-p, %p->%p->%p",
- hi_from->handle, hi_to->handle, cList->channel->channel->name,
- cList->u_prev, cList, cList->u_next,
- (cList2?cList2->u_prev:0), cList2, (cList2?cList2->u_next:0));
if (cList2 && (cList2->access >= cList->access)) {
+ log_module(NS_LOG, LOG_INFO, "Merge: %s had only %d access in %s (versus %d for %s)", hi_from->handle, cList->access, cList->channel->channel->name, cList2->access, hi_to->handle);
/* keep cList2 in hi_to; remove cList from hi_from */
- log_module(NS_LOG, LOG_DEBUG, "Deleting %p", cList);
del_channel_user(cList, 1);
} else {
if (cList2) {
+ log_module(NS_LOG, LOG_INFO, "Merge: %s had only %d access in %s (versus %d for %s)", hi_to->handle, cList2->access, cList->channel->channel->name, cList->access, hi_from->handle);
/* remove the lower-ranking cList2 from hi_to */
- log_module(NS_LOG, LOG_DEBUG, "Deleting %p", cList2);
del_channel_user(cList2, 1);
+ } else {
+ log_module(NS_LOG, LOG_INFO, "Merge: %s had no access in %s", hi_to->handle, cList->channel->channel->name);
}
/* cList needs to be moved from hi_from to hi_to */
cList->handle = hi_to;
if (hi_to->channels)
hi_to->channels->u_prev = cList;
hi_to->channels = cList;
- log_module(NS_LOG, LOG_DEBUG, "Now %p->%p->%p",
- cList->u_prev, cList, cList->u_next);
}
}
if (hi_from->lastseen > hi_to->lastseen)
hi_to->lastseen = hi_from->lastseen;
+ /* New karma is the sum of the two original karmas. */
+ hi_to->karma += hi_from->karma;
+
+ /* Does a fakehost carry over? (This intentionally doesn't set it
+ * for users previously attached to hi_to. They'll just have to
+ * reconnect.)
+ */
+ if (hi_from->fakehost && !hi_to->fakehost)
+ hi_to->fakehost = strdup(hi_from->fakehost);
+
/* Notify of success. */
sprintf(buffer, "%s (%s) merged account %s into %s.", user->nick, user->handle_info->handle, hi_from->handle, hi_to->handle);
reply("NSMSG_HANDLES_MERGED", hi_from->handle, hi_to->handle);
}
struct nickserv_discrim {
- unsigned int limit, min_level, max_level;
unsigned long flags_on, flags_off;
time_t min_registered, max_registered;
time_t lastseen;
- enum { SUBSET, EXACT, SUPERSET } hostmask_type;
+ unsigned int limit;
+ int min_level, max_level;
+ int min_karma, max_karma;
+ enum { SUBSET, EXACT, SUPERSET, LASTQUIT } hostmask_type;
const char *nickmask;
const char *hostmask;
+ const char *fakehostmask;
const char *handlemask;
const char *emailmask;
};
discrim = malloc(sizeof(*discrim));
memset(discrim, 0, sizeof(*discrim));
discrim->min_level = 0;
- discrim->max_level = ~0;
+ discrim->max_level = INT_MAX;
discrim->limit = 50;
discrim->min_registered = 0;
discrim->max_registered = INT_MAX;
- discrim->lastseen = now;
+ discrim->lastseen = LONG_MAX;
+ discrim->min_karma = INT_MIN;
+ discrim->max_karma = INT_MAX;
for (i=0; i<argc; i++) {
if (i == argc - 1) {
goto fail;
}
if (!irccasecmp(argv[i], "limit")) {
- discrim->limit = atoi(argv[++i]);
+ discrim->limit = strtoul(argv[++i], NULL, 0);
} else if (!irccasecmp(argv[i], "flags")) {
nickserv_modify_handle_flags(user, nickserv, argv[++i], &discrim->flags_on, &discrim->flags_off);
} else if (!irccasecmp(argv[i], "registered")) {
goto fail;
}
discrim->hostmask_type = SUPERSET;
+ } else if (!irccasecmp(argv[i], "lastquit") || !irccasecmp(argv[i], "lastauth")) {
+ if (i == argc - 1) {
+ send_message(user, nickserv, "MSG_MISSING_PARAMS", argv[i]);
+ goto fail;
+ }
+ discrim->hostmask_type = LASTQUIT;
} else {
i--;
discrim->hostmask_type = SUPERSET;
}
discrim->hostmask = argv[++i];
+ } else if (!irccasecmp(argv[i], "fakehost")) {
+ if (!irccasecmp(argv[++i], "*")) {
+ discrim->fakehostmask = 0;
+ } else {
+ discrim->fakehostmask = argv[i];
+ }
} else if (!irccasecmp(argv[i], "handlemask") || !irccasecmp(argv[i], "accountmask")) {
if (!irccasecmp(argv[++i], "*")) {
discrim->handlemask = 0;
} else {
send_message(user, nickserv, "MSG_INVALID_CRITERIA", cmp);
}
+ } else if (!irccasecmp(argv[i], "karma")) {
+ const char *cmp = argv[++i];
+ if (cmp[0] == '<') {
+ if (cmp[1] == '=') {
+ discrim->max_karma = strtoul(cmp+2, NULL, 0);
+ } else {
+ discrim->max_karma = strtoul(cmp+1, NULL, 0) - 1;
+ }
+ } else if (cmp[0] == '=') {
+ discrim->min_karma = discrim->max_karma = strtoul(cmp+1, NULL, 0);
+ } else if (cmp[0] == '>') {
+ if (cmp[1] == '=') {
+ discrim->min_karma = strtoul(cmp+2, NULL, 0);
+ } else {
+ discrim->min_karma = strtoul(cmp+1, NULL, 0) + 1;
+ }
+ } else {
+ send_message(user, nickserv, "MSG_INVALID_CRITERIA", cmp);
+ }
} else {
send_message(user, nickserv, "MSG_INVALID_CRITERIA", argv[i]);
goto fail;
|| (discrim->max_registered < hi->registered)
|| (discrim->lastseen < (hi->users?now:hi->lastseen))
|| (discrim->handlemask && !match_ircglob(hi->handle, discrim->handlemask))
+ || (discrim->fakehostmask && (!hi->fakehost || !match_ircglob(hi->fakehost, discrim->fakehostmask)))
|| (discrim->emailmask && (!hi->email_addr || !match_ircglob(hi->email_addr, discrim->emailmask)))
|| (discrim->min_level > hi->opserv_level)
- || (discrim->max_level < hi->opserv_level)) {
+ || (discrim->max_level < hi->opserv_level)
+ || (discrim->min_karma > hi->karma)
+ || (discrim->max_karma < hi->karma)
+ ) {
return 0;
}
if (discrim->hostmask) {
&& !irccasecmp(discrim->hostmask, mask)) break;
else if ((discrim->hostmask_type == SUPERSET)
&& (match_ircglobs(mask, discrim->hostmask))) break;
+ else if ((discrim->hostmask_type == LASTQUIT)
+ && (match_ircglobs(discrim->hostmask, hi->last_quit_host))) break;
}
if (i==hi->masks->used) return 0;
}
}
table_send(cmd->parent->bot, user->nick, 0, NULL, tbl);
reply("MSG_MATCH_COUNT", hil.used);
- for (ii = 0; ii < hil.used; )
- free(tbl.contents[++ii]);
+ for (ii = 0; ii < hil.used; ii++)
+ free(tbl.contents[ii]);
free(tbl.contents);
free(hil.list);
}
struct string_list *masks, *slist;
struct handle_info *hi;
struct userNode *authed_users;
+ struct userData *channels;
unsigned long int id;
unsigned int ii;
dict_t subdb;
}
if ((hi = get_handle_info(handle))) {
authed_users = hi->users;
+ channels = hi->channels;
hi->users = NULL;
+ hi->channels = NULL;
dict_remove(nickserv_handle_dict, hi->handle);
} else {
authed_users = NULL;
+ channels = NULL;
}
hi = register_handle(handle, str, id);
if (authed_users) {
authed_users = authed_users->next_authed;
}
}
+ hi->channels = channels;
masks = database_get_data(obj, KEY_MASKS, RECDB_STRING_LIST);
hi->masks = masks ? string_list_copy(masks) : alloc_string_list(1);
str = database_get_data(obj, KEY_MAXLOGINS, RECDB_QSTRING);
str = database_get_data(obj, KEY_OPSERV_LEVEL, RECDB_QSTRING);
hi->opserv_level = str ? strtoul(str, NULL, 0) : 0;
str = database_get_data(obj, KEY_INFO, RECDB_QSTRING);
- if (str) hi->infoline = strdup(str);
+ if (str)
+ hi->infoline = strdup(str);
str = database_get_data(obj, KEY_REGISTER_ON, RECDB_QSTRING);
hi->registered = str ? (time_t)strtoul(str, NULL, 0) : now;
str = database_get_data(obj, KEY_LAST_SEEN, RECDB_QSTRING);
hi->lastseen = str ? (time_t)strtoul(str, NULL, 0) : hi->registered;
+ str = database_get_data(obj, KEY_KARMA, RECDB_QSTRING);
+ hi->karma = str ? strtoul(str, NULL, 0) : 0;
/* We want to read the nicks even if disable_nicks is set. This is so
* that we don't lose the nick data entirely. */
slist = database_get_data(obj, KEY_NICKS, RECDB_STRING_LIST);
}
str = database_get_data(obj, KEY_USERLIST_STYLE, RECDB_QSTRING);
hi->userlist_style = str ? str[0] : HI_STYLE_ZOOT;
- str = database_get_data(obj, KEY_ANNOUNCEMENTS, RECDB_QSTRING);
- hi->announcements = str ? str[0] : '?';
str = database_get_data(obj, KEY_SCREEN_WIDTH, RECDB_QSTRING);
hi->screen_width = str ? strtoul(str, NULL, 0) : 0;
str = database_get_data(obj, KEY_TABLE_WIDTH, RECDB_QSTRING);
hi->table_width = str ? strtoul(str, NULL, 0) : 0;
str = database_get_data(obj, KEY_LAST_QUIT_HOST, RECDB_QSTRING);
- if (!str) str = database_get_data(obj, KEY_LAST_AUTHED_HOST, RECDB_QSTRING);
- if (str) safestrncpy(hi->last_quit_host, str, sizeof(hi->last_quit_host));
+ if (!str)
+ str = database_get_data(obj, KEY_LAST_AUTHED_HOST, RECDB_QSTRING);
+ if (str)
+ safestrncpy(hi->last_quit_host, str, sizeof(hi->last_quit_host));
str = database_get_data(obj, KEY_EMAIL_ADDR, RECDB_QSTRING);
- if (str) nickserv_set_email_addr(hi, str);
+ if (str)
+ nickserv_set_email_addr(hi, str);
str = database_get_data(obj, KEY_EPITHET, RECDB_QSTRING);
- if (str) hi->epithet = strdup(str);
+ if (str)
+ hi->epithet = strdup(str);
+ str = database_get_data(obj, KEY_FAKEHOST, RECDB_QSTRING);
+ if (str)
+ hi->fakehost = strdup(str);
+ /* Read the "cookie" sub-database (if it exists). */
subdb = database_get_data(obj, KEY_COOKIE, RECDB_OBJECT);
if (subdb) {
const char *data, *type, *expires, *cookie_str;
else
nickserv_free_cookie(cookie);
}
+ /* Read the "notes" sub-database (if it exists). */
+ subdb = database_get_data(obj, KEY_NOTES, RECDB_OBJECT);
+ if (subdb) {
+ dict_iterator_t it;
+ struct handle_note *last_note;
+ struct handle_note *note;
+
+ last_note = NULL;
+ for (it = dict_first(subdb); it; it = iter_next(it)) {
+ const char *expires;
+ const char *setter;
+ const char *text;
+ const char *set;
+ const char *id;
+ dict_t notedb;
+
+ id = iter_key(it);
+ notedb = GET_RECORD_OBJECT((struct record_data*)iter_data(it));
+ if (!notedb) {
+ log_module(NS_LOG, LOG_ERROR, "Malformed note %s for account %s; ignoring note.", id, hi->handle);
+ continue;
+ }
+ expires = database_get_data(notedb, KEY_NOTE_EXPIRES, RECDB_QSTRING);
+ setter = database_get_data(notedb, KEY_NOTE_SETTER, RECDB_QSTRING);
+ text = database_get_data(notedb, KEY_NOTE_NOTE, RECDB_QSTRING);
+ set = database_get_data(notedb, KEY_NOTE_SET, RECDB_QSTRING);
+ if (!setter || !text || !set) {
+ log_module(NS_LOG, LOG_ERROR, "Missing field(s) from note %s for account %s; ignoring note.", id, hi->handle);
+ continue;
+ }
+ note = calloc(1, sizeof(*note) + strlen(text));
+ note->next = NULL;
+ note->expires = expires ? strtoul(expires, NULL, 10) : 0;
+ note->set = strtoul(set, NULL, 10);
+ note->id = strtoul(id, NULL, 10);
+ safestrncpy(note->setter, setter, sizeof(note->setter));
+ strcpy(note->note, text);
+ if (last_note)
+ last_note->next = note;
+ else
+ hi->notes = note;
+ last_note = note;
+ }
+ }
}
static int
stop.tv_sec -= start.tv_sec;
stop.tv_usec -= start.tv_usec;
if (stop.tv_usec < 0) {
- stop.tv_sec -= 1;
- stop.tv_usec += 1000000;
+ stop.tv_sec -= 1;
+ stop.tv_usec += 1000000;
}
reply("NSMSG_DB_MERGED", argv[1], stop.tv_sec, stop.tv_usec/1000);
return 1;
dict_iterator_t it;
if (!(conf_node = conf_get_data(NICKSERV_CONF_NAME, RECDB_OBJECT))) {
- log_module(NS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME);
- return;
+ log_module(NS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", NICKSERV_CONF_NAME);
+ return;
}
str = database_get_data(conf_node, KEY_VALID_HANDLE_REGEX, RECDB_QSTRING);
- if (!str) str = database_get_data(conf_node, KEY_VALID_ACCOUNT_REGEX, RECDB_QSTRING);
- if (nickserv_conf.valid_handle_regex_set) regfree(&nickserv_conf.valid_handle_regex);
+ if (!str)
+ str = database_get_data(conf_node, KEY_VALID_ACCOUNT_REGEX, RECDB_QSTRING);
+ if (nickserv_conf.valid_handle_regex_set)
+ regfree(&nickserv_conf.valid_handle_regex);
if (str) {
int err = regcomp(&nickserv_conf.valid_handle_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
nickserv_conf.valid_handle_regex_set = !err;
nickserv_conf.valid_handle_regex_set = 0;
}
str = database_get_data(conf_node, KEY_VALID_NICK_REGEX, RECDB_QSTRING);
- if (nickserv_conf.valid_nick_regex_set) regfree(&nickserv_conf.valid_nick_regex);
+ if (nickserv_conf.valid_nick_regex_set)
+ regfree(&nickserv_conf.valid_nick_regex);
if (str) {
int err = regcomp(&nickserv_conf.valid_nick_regex, str, REG_EXTENDED|REG_ICASE|REG_NOSUB);
nickserv_conf.valid_nick_regex_set = !err;
nickserv_conf.valid_nick_regex_set = 0;
}
str = database_get_data(conf_node, KEY_NICKS_PER_HANDLE, RECDB_QSTRING);
- if (!str) str = database_get_data(conf_node, KEY_NICKS_PER_ACCOUNT, RECDB_QSTRING);
+ if (!str)
+ str = database_get_data(conf_node, KEY_NICKS_PER_ACCOUNT, RECDB_QSTRING);
nickserv_conf.nicks_per_handle = str ? strtoul(str, NULL, 0) : 4;
str = database_get_data(conf_node, KEY_DISABLE_NICKS, RECDB_QSTRING);
nickserv_conf.disable_nicks = str ? strtoul(str, NULL, 0) : 0;
nickserv_conf.modoper_level = str ? strtoul(str, NULL, 0) : 900;
str = database_get_data(conf_node, KEY_SET_EPITHET_LEVEL, RECDB_QSTRING);
nickserv_conf.set_epithet_level = str ? strtoul(str, NULL, 0) : 1;
+ str = database_get_data(conf_node, KEY_SET_TITLE_LEVEL, RECDB_QSTRING);
+ nickserv_conf.set_title_level = str ? strtoul(str, NULL, 0) : 900;
+ str = database_get_data(conf_node, KEY_SET_FAKEHOST_LEVEL, RECDB_QSTRING);
+ nickserv_conf.set_fakehost_level = str ? strtoul(str, NULL, 0) : 1000;
str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_FREQ, RECDB_QSTRING);
- if (!str) str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_FREQ, RECDB_QSTRING);
+ if (!str)
+ str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_FREQ, RECDB_QSTRING);
nickserv_conf.handle_expire_frequency = str ? ParseInterval(str) : 86400;
str = database_get_data(conf_node, KEY_HANDLE_EXPIRE_DELAY, RECDB_QSTRING);
- if (!str) str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
+ if (!str)
+ str = database_get_data(conf_node, KEY_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
nickserv_conf.handle_expire_delay = str ? ParseInterval(str) : 86400*30;
str = database_get_data(conf_node, KEY_NOCHAN_HANDLE_EXPIRE_DELAY, RECDB_QSTRING);
- if (!str) str = database_get_data(conf_node, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
+ if (!str)
+ str = database_get_data(conf_node, KEY_NOCHAN_ACCOUNT_EXPIRE_DELAY, RECDB_QSTRING);
nickserv_conf.nochan_handle_expire_delay = str ? ParseInterval(str) : 86400*15;
str = database_get_data(conf_node, "warn_clone_auth", RECDB_QSTRING);
nickserv_conf.warn_clone_auth = str ? !disabled_string(str) : 1;
nickserv_conf.default_maxlogins = str ? strtoul(str, NULL, 0) : 2;
str = database_get_data(conf_node, "hard_maxlogins", RECDB_QSTRING);
nickserv_conf.hard_maxlogins = str ? strtoul(str, NULL, 0) : 10;
+ str = database_get_data(conf_node, KEY_OUNREGISTER_INACTIVE, RECDB_QSTRING);
+ nickserv_conf.ounregister_inactive = str ? ParseInterval(str) : 86400*28;
+ str = database_get_data(conf_node, KEY_OUNREGISTER_FLAGS, RECDB_QSTRING);
+ if (!str)
+ str = "ShgsfnHbu";
+ nickserv_conf.ounregister_flags = 0;
+ while(*str) {
+ unsigned int pos = handle_inverse_flags[(unsigned char)*str];
+ str++;
+ if(pos)
+ nickserv_conf.ounregister_flags |= 1 << (pos - 1);
+ }
if (!nickserv_conf.disable_nicks) {
str = database_get_data(conf_node, "reclaim_action", RECDB_QSTRING);
nickserv_conf.reclaim_action = str ? reclaim_action_from_string(str) : RECLAIM_NONE;
nickserv_conf.handles_per_email = str ? strtoul(str, NULL, 0) : 1;
str = database_get_data(conf_node, KEY_EMAIL_SEARCH_LEVEL, RECDB_QSTRING);
nickserv_conf.email_search_level = str ? strtoul(str, NULL, 0) : 600;
+ str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING);
+ nickserv_conf.titlehost_suffix = str ? str : "example.net";
str = conf_get_data("server/network", RECDB_QSTRING);
nickserv_conf.network_name = str ? str : "some IRC network";
if (!nickserv_conf.auth_policer_params) {
static void
nickserv_reclaim(struct userNode *user, struct nick_info *ni, enum reclaim_action action) {
+ const char *msg;
char newnick[NICKLEN+1];
assert(user);
irc_svsnick(nickserv, user, newnick);
break;
case RECLAIM_KILL:
- irc_kill(nickserv, user, "NSMSG_RECLAIM_KILL");
+ msg = user_find_message(user, "NSMSG_RECLAIM_KILL");
+ DelUser(user, nickserv, 1, msg);
break;
}
}
nickserv_define_func("USERINFO", cmd_userinfo, -1, 1, 0);
nickserv_define_func("RENAME", cmd_rename_handle, -1, 1, 0);
nickserv_define_func("VACATION", cmd_vacation, -1, 1, 0);
- nickserv_define_func("MERGE", cmd_merge, 0, 1, 0);
+ nickserv_define_func("MERGE", cmd_merge, 750, 1, 0);
+ nickserv_define_func("ADDNOTE", cmd_addnote, 0, 1, 0);
+ nickserv_define_func("DELNOTE", cmd_delnote, 0, 1, 0);
+ nickserv_define_func("NOTES", cmd_notes, 0, 1, 0);
if (!nickserv_conf.disable_nicks) {
- /* nick management commands */
- nickserv_define_func("REGNICK", cmd_regnick, -1, 1, 0);
- nickserv_define_func("OREGNICK", cmd_oregnick, 0, 1, 0);
- nickserv_define_func("UNREGNICK", cmd_unregnick, -1, 1, 0);
- nickserv_define_func("OUNREGNICK", cmd_ounregnick, 0, 1, 0);
- nickserv_define_func("NICKINFO", cmd_nickinfo, -1, 1, 0);
+ /* nick management commands */
+ nickserv_define_func("REGNICK", cmd_regnick, -1, 1, 0);
+ nickserv_define_func("OREGNICK", cmd_oregnick, 0, 1, 0);
+ nickserv_define_func("UNREGNICK", cmd_unregnick, -1, 1, 0);
+ nickserv_define_func("OUNREGNICK", cmd_ounregnick, 0, 1, 0);
+ nickserv_define_func("NICKINFO", cmd_nickinfo, -1, 1, 0);
nickserv_define_func("RECLAIM", cmd_reclaim, -1, 1, 0);
}
if (nickserv_conf.email_enabled) {
dict_insert(nickserv_opt_dict, "ACCESS", opt_level);
dict_insert(nickserv_opt_dict, "LEVEL", opt_level);
dict_insert(nickserv_opt_dict, "EPITHET", opt_epithet);
- dict_insert(nickserv_opt_dict, "ANNOUNCEMENTS", opt_announcements);
+ if (nickserv_conf.titlehost_suffix) {
+ dict_insert(nickserv_opt_dict, "TITLE", opt_title);
+ dict_insert(nickserv_opt_dict, "FAKEHOST", opt_fakehost);
+ }
dict_insert(nickserv_opt_dict, "MAXLOGINS", opt_maxlogins);
dict_insert(nickserv_opt_dict, "LANGUAGE", opt_language);
+ dict_insert(nickserv_opt_dict, "KARMA", opt_karma);
+ nickserv_define_func("OSET KARMA", NULL, 0, 1, 0);
nickserv_handle_dict = dict_new();
dict_set_free_keys(nickserv_handle_dict, free);
dict_set_free_keys(nickserv_id_dict, free);
nickserv_nick_dict = dict_new();
- dict_set_free_data(nickserv_nick_dict, free_nick_info);
+ dict_set_free_data(nickserv_nick_dict, free);
nickserv_allow_auth_dict = dict_new();
userList_init(&curr_helpers);
if (nick) {
- nickserv = AddService(nick, "Nick Services");
- nickserv_service = service_register(nickserv, 0);
+ const char *modes = conf_get_data("services/nickserv/modes", RECDB_QSTRING);
+ nickserv = AddLocalUser(nick, nick, NULL, "Nick Services", modes);
+ nickserv_service = service_register(nickserv);
}
saxdb_register("NickServ", nickserv_saxdb_read, nickserv_saxdb_write);
reg_exit_func(nickserv_db_cleanup);