X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/d334709935bf3ed5dcab9621e66524d7d96613de..4e49624c75f3a3d458591e611adcb35bf4654368:/src/chanserv.c diff --git a/src/chanserv.c b/src/chanserv.c index da9298e..e934108 100644 --- a/src/chanserv.c +++ b/src/chanserv.c @@ -218,6 +218,7 @@ static const struct message_entry msgtab[] = { { "CSMSG_NO_SELF_CLVL", "You cannot change your own access." }, { "CSMSG_NO_BUMP_ACCESS", "You cannot give users access greater than or equal to your own." }, { "CSMSG_MULTIPLE_OWNERS", "There is more than one owner in %s; please use $bCLVL$b, $bDELOWNER$b and/or $bADDOWNER$b instead." }, + { "CSMSG_NO_OWNER", "There is no owner for %s; please use $bCLVL$b and/or $bADDOWNER$b instead." }, { "CSMSG_TRANSFER_WAIT", "You must wait %s before you can give ownership of $b%s$b to someone else." }, { "CSMSG_NO_TRANSFER_SELF", "You cannot give ownership to your own account." }, { "CSMSG_OWNERSHIP_GIVEN", "Ownership of $b%s$b has been transferred to account $b%s$b." }, @@ -296,6 +297,7 @@ static const struct message_entry msgtab[] = { { "CSMSG_USET_AUTOOP", "$bAutoOp $b %s" }, { "CSMSG_USET_AUTOVOICE", "$bAutoVoice $b %s" }, { "CSMSG_USET_AUTOINVITE", "$bAutoInvite $b %s" }, + { "CSMSG_USET_AUTOJOIN", "$bAutoJoin $b %s" }, { "CSMSG_USET_INFO", "$bInfo $b %s" }, { "CSMSG_USER_PROTECTED", "Sorry, $b%s$b is protected." }, @@ -316,6 +318,7 @@ static const struct message_entry msgtab[] = { { "CSMSG_AUTOMODE_HOP", "#1 plus give halfops to everyone." }, { "CSMSG_AUTOMODE_OP", "#1 plus give ops to everyone (not advised)" }, { "CSMSG_AUTOMODE_MUTE", "Give half-op to halfops, and op to ops only." }, + { "CSMSG_AUTOMODE_ONLYVOICE", "Just voice everyone with access." }, { "CSMSG_PROTECT_ALL", "Non-users and users will be protected from those of equal or lower access." }, { "CSMSG_PROTECT_EQUAL", "Users will be protected from those of equal or lower access." }, @@ -353,6 +356,7 @@ static const struct message_entry msgtab[] = { { "CSMSG_INVITED_USER", "Invited $b%s$b to join %s." }, { "CSMSG_INVITING_YOU_REASON", "$b%s$b invites you to join %s: %s" }, { "CSMSG_INVITING_YOU", "$b%s$b invites you to join %s." }, + { "CSMSG_CANNOT_INVITE", "You cannot invite %s to %s." }, { "CSMSG_ALREADY_PRESENT", "%s is already in $b%s$b." }, { "CSMSG_YOU_ALREADY_PRESENT", "You are already in $b%s$b." }, { "CSMSG_LOW_CHANNEL_ACCESS", "You lack sufficient access in %s to use this command." }, @@ -512,6 +516,8 @@ static const struct message_entry msgtab[] = { /* Other things */ { "CSMSG_EVENT_SEARCH_RESULTS", "$bChannel Events for %s$b" }, { "CSMSG_LAST_INVALID", "Invalid argument. must be 1-200" }, + { "CSMSG_DEFCON_NO_NEW_CHANNELS", "You cannot register new channels at this time, please try again soon." }, + { "CSMSG_DEFCON_NO_MODE_CHANGE", "You cannot change the MODE at this time, please try again soon." }, { NULL, NULL } }; @@ -683,7 +689,8 @@ struct charOptionValues { { 'v', "CSMSG_AUTOMODE_VOICE" }, { 'h', "CSMSG_AUTOMODE_HOP" }, { 'o', "CSMSG_AUTOMODE_OP" }, - { 'm', "CSMSG_AUTOMODE_MUTE" } + { 'm', "CSMSG_AUTOMODE_MUTE" }, + { 'l', "CSMSG_AUTOMODE_ONLYVOICE" } }, protectValues[] = { { 'a', "CSMSG_PROTECT_ALL" }, { 'e', "CSMSG_PROTECT_EQUAL" }, @@ -1675,7 +1682,7 @@ protect_user(const struct userNode *victim, const struct userNode *aggressor, st } static int -validate_op(struct userNode *user, struct chanNode *channel, struct userNode *victim) +validate_op(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, struct userNode *victim) { struct chanData *cData = channel->channel_info; struct userData *cs_victim; @@ -1684,7 +1691,10 @@ validate_op(struct userNode *user, struct chanNode *channel, struct userNode *vi || (cs_victim->access < UL_OP /* cData->lvlOpts[lvlGiveOps]*/)) && !check_user_level(channel, user, lvlEnfOps, 0, 0)) { - send_message(user, chanserv, "CSMSG_OPBY_LOCKED"); + if(cmd) + reply("CSMSG_OPBY_LOCKED"); + else + send_message(user, chanserv, "CSMSG_OPBY_LOCKED"); return 0; } @@ -1692,7 +1702,7 @@ validate_op(struct userNode *user, struct chanNode *channel, struct userNode *vi } static int -validate_halfop(struct userNode *user, struct chanNode *channel, struct userNode *victim) +validate_halfop(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, struct userNode *victim) { struct chanData *cData = channel->channel_info; struct userData *cs_victim; @@ -1701,7 +1711,7 @@ validate_halfop(struct userNode *user, struct chanNode *channel, struct userNode || (cs_victim->access < UL_HALFOP /* cData->lvlOpts[lvlGiveHalfOps] */)) && !check_user_level(channel, user, lvlEnfHalfOps, 0, 0)) { - send_message(user, chanserv, "CSMSG_HOPBY_LOCKED"); + reply("CSMSG_HOPBY_LOCKED"); return 0; } @@ -1710,17 +1720,17 @@ validate_halfop(struct userNode *user, struct chanNode *channel, struct userNode static int -validate_deop(struct userNode *user, struct chanNode *channel, struct userNode *victim) +validate_deop(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, struct userNode *victim) { if(IsService(victim)) { - send_message(user, chanserv, "MSG_SERVICE_IMMUNE", victim->nick); + reply("MSG_SERVICE_IMMUNE", victim->nick); return 0; } if(protect_user(victim, user, channel->channel_info)) { - send_message(user, chanserv, "CSMSG_USER_PROTECTED", victim->nick); + reply("CSMSG_USER_PROTECTED", victim->nick); return 0; } @@ -1728,17 +1738,17 @@ validate_deop(struct userNode *user, struct chanNode *channel, struct userNode * } static int -validate_dehop(struct userNode *user, struct chanNode *channel, struct userNode *victim) +validate_dehop(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, struct userNode *victim) { if(IsService(victim)) { - send_message(user, chanserv, "MSG_SERVICE_IMMUNE", victim->nick); + reply("MSG_SERVICE_IMMUNE", victim->nick); return 0; } if(protect_user(victim, user, channel->channel_info)) { - send_message(user, chanserv, "CSMSG_USER_PROTECTED", victim->nick); + reply("CSMSG_USER_PROTECTED", victim->nick); return 0; } @@ -1959,6 +1969,10 @@ static CHANSERV_FUNC(cmd_register) struct do_not_register *dnr; unsigned int n; + if (checkDefCon(DEFCON_NO_NEW_CHANNELS) && !IsOper(user)) { + reply("CSMSG_DEFCON_NO_NEW_CHANNELS"); + return 0; + } if(channel) { @@ -2095,10 +2109,10 @@ static CHANSERV_FUNC(cmd_register) if(handle != user->handle_info) reply("CSMSG_PROXY_SUCCESS", handle->handle, channel->name); else - reply("CSMSG_REG_SUCCESS", channel->name); sprintf(reason, "%s registered to %s by %s.", channel->name, handle->handle, user->handle_info->handle); - global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason); + global_message_args(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, "CSMSG_REGISTERED_TO", channel->name, + handle->handle, user->handle_info->handle); return 1; } @@ -2204,7 +2218,6 @@ static CHANSERV_FUNC(cmd_move) struct chanNode *target; struct modeNode *mn; struct userData *uData; - char reason[MAXLEN]; struct do_not_register *dnr; int chanserv_join = 0, spamserv_join; @@ -2287,16 +2300,18 @@ static CHANSERV_FUNC(cmd_move) if (chanserv_join) ss_cs_join_channel(target, spamserv_join); - sprintf(reason, "%s moved to %s by %s.", channel->name, target->name, user->handle_info->handle); if(!IsSuspended(target->channel_info)) { char reason2[MAXLEN]; - sprintf(reason2, "Channel moved to %s by %s.", target->name, user->handle_info->handle); - DelChannelUser(chanserv, channel, reason2, 0); + sprintf(reason2, "Channel moved to %s by %s.", target->name, user->handle_info->handle); + DelChannelUser(chanserv, channel, reason2, 0); } + UnlockChannel(channel); LockChannel(target); - global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason); + global_message_args(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, "CSMSG_CHANNEL_MOVED", + channel->name, target->name, user->handle_info->handle); + reply("CSMSG_MOVE_SUCCESS", target->name); return 1; } @@ -2794,7 +2809,7 @@ static CHANSERV_FUNC(cmd_mdelhalfop) /* trim_lamers.. */ static int -cmd_trim_bans(struct userNode *user, struct chanNode *channel, unsigned long duration) +cmd_trim_bans(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, unsigned long duration) { struct banData *bData, *next; char interval[INTERVALLEN]; @@ -2815,12 +2830,12 @@ cmd_trim_bans(struct userNode *user, struct chanNode *channel, unsigned long dur } intervalString(interval, duration, user->handle_info); - send_message(user, chanserv, "CSMSG_TRIMMED_LAMERS", count, channel->name, interval); + reply("CSMSG_TRIMMED_LAMERS", count, channel->name, interval); return 1; } static int -cmd_trim_users(struct userNode *user, struct chanNode *channel, unsigned short min_access, unsigned short max_access, unsigned long duration, int vacation) +cmd_trim_users(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, unsigned short min_access, unsigned short max_access, unsigned long duration, int vacation) { struct userData *actor, *uData, *next; char interval[INTERVALLEN]; @@ -2830,13 +2845,13 @@ cmd_trim_users(struct userNode *user, struct chanNode *channel, unsigned short m actor = GetChannelUser(channel->channel_info, user->handle_info); if(min_access > max_access) { - send_message(user, chanserv, "CSMSG_BAD_RANGE", min_access, max_access); + reply("CSMSG_BAD_RANGE", min_access, max_access); return 0; } if((actor->access <= max_access) && !IsHelping(user)) { - send_message(user, chanserv, "CSMSG_NO_ACCESS"); + reply("CSMSG_NO_ACCESS"); return 0; } @@ -2864,7 +2879,7 @@ cmd_trim_users(struct userNode *user, struct chanNode *channel, unsigned short m min_access = 1; max_access = (actor->access > UL_OWNER) ? UL_OWNER : (actor->access - 1); } - send_message(user, chanserv, "CSMSG_TRIMMED_USERS", count, min_access, max_access, channel->name, intervalString(interval, duration, user->handle_info)); + reply("CSMSG_TRIMMED_USERS", count, min_access, max_access, channel->name, intervalString(interval, duration, user->handle_info)); return 1; } @@ -2886,22 +2901,22 @@ static CHANSERV_FUNC(cmd_trim) if(!irccasecmp(argv[1], "lamers")) { - cmd_trim_bans(user, channel, duration); /* trim_lamers.. */ + cmd_trim_bans(cmd, user, channel, duration); /* trim_lamers.. */ return 1; } else if(!irccasecmp(argv[1], "users")) { - cmd_trim_users(user, channel, 0, 0, duration, vacation); + cmd_trim_users(cmd, user, channel, 0, 0, duration, vacation); return 1; } else if(parse_level_range(&min_level, &max_level, argv[1])) { - cmd_trim_users(user, channel, min_level, max_level, duration, vacation); + cmd_trim_users(cmd, user, channel, min_level, max_level, duration, vacation); return 1; } else if((min_level = user_level_from_name(argv[1], UL_OWNER))) { - cmd_trim_users(user, channel, min_level, min_level, duration, vacation); + cmd_trim_users(cmd, user, channel, min_level, min_level, duration, vacation); return 1; } else @@ -3021,7 +3036,7 @@ static CHANSERV_FUNC(cmd_downall) return cmd_all(CSFUNC_ARGS, cmd_down); } -typedef int validate_func_t(struct userNode *user, struct chanNode *channel, struct userNode *victim); +typedef int validate_func_t(struct svccmd *cmd, struct userNode *user, struct chanNode *channel, struct userNode *victim); typedef void process_func_t(unsigned int num, struct userNode **newops, struct chanNode *channel, struct userNode *who, int announce); static int @@ -3041,7 +3056,7 @@ modify_users(struct userNode *user, struct chanNode *channel, unsigned int argc, change->args[valid].u.member = GetUserMode(channel, victim); if(!change->args[valid].u.member) continue; - if(validate && !validate(user, channel, victim)) + if(validate && !validate(cmd, user, channel, victim)) continue; valid++; } @@ -3743,6 +3758,8 @@ static CHANSERV_FUNC(cmd_myaccess) } if(IsUserAutoInvite(uData) && (uData->access >= cData->lvlOpts[lvlInviteMe])) string_buffer_append(&sbuf, 'i'); + if(IsUserAutoJoin(uData) && (uData->access >= cData->lvlOpts[lvlInviteMe])) + string_buffer_append(&sbuf, 'j'); if(uData->info) string_buffer_append_printf(&sbuf, ")] %s", uData->info); else @@ -4382,6 +4399,7 @@ static CHANSERV_FUNC(cmd_topic) { if(cData->topic) { + /*XXX Why would we ever want to send chanserv as the setter? I dont understand -Rubin */ SetChannelTopic(channel, chanserv, p10 ? user : chanserv, cData->topic, 1); reply("CSMSG_TOPIC_SET", cData->topic); return 1; @@ -4442,6 +4460,11 @@ static CHANSERV_FUNC(cmd_mode) if(argc < 2) { + if (checkDefCon(DEFCON_NO_MODE_CHANGE) && !IsOper(user)) { + reply("CSMSG_DEFCON_NO_MODE_CHANGE"); + return 0; + } + change = &channel->channel_info->modes; if(change->modes_set || change->modes_clear) { modcmd_chanmode_announce(change); @@ -4515,6 +4538,17 @@ static CHANSERV_FUNC(cmd_invite) else send_message(invite, chanserv, "CSMSG_INVITING_YOU", user->nick, channel->name); } + + if (invite->handle_info && invite->handle_info->ignores->used && (argc > 1)) { + unsigned int i; + for (i=0; i < invite->handle_info->ignores->used; i++) { + if (user_matches_glob(user, invite->handle_info->ignores->list[i], MATCH_USENICK)) { + reply("CSMSG_CANNOT_INVITE", argv[1], channel->name); + return 0; + } + } + } + irc_invite(chanserv, invite, channel); if(argc > 1) reply("CSMSG_INVITED_USER", argv[1], channel->name); @@ -4663,9 +4697,9 @@ static CHANSERV_FUNC(cmd_info) reply("CSMSG_CHANNEL_VISITED", intervalString(buffer, now - cData->visited, user->handle_info)); privileged = IsStaff(user); - if(privileged) + /* if(privileged) */ reply("CSMSG_CHANNEL_REGISTERED", intervalString(buffer, now - cData->registered, user->handle_info)); - if(((uData && uData->access >= UL_COOWNER) || privileged) && cData->registrar) + if(/*((uData && uData->access >= UL_COOWNER) || privileged) && */cData->registrar) reply("CSMSG_CHANNEL_REGISTRAR", cData->registrar); if(privileged && (dnr = chanserv_is_dnr(channel->name, NULL))) @@ -5374,8 +5408,9 @@ static CHANSERV_FUNC(cmd_csuspend) suspended->previous->revoked = now; if(suspended->previous->expires) timeq_del(suspended->previous->expires, chanserv_expire_suspension, suspended->previous, 0); - sprintf(reason, "%s suspension modified by %s.", channel->name, suspended->suspender); - global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason); + + global_message_args(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, "CSMSG_SUSPENSION_MODIFIED", + channel->name, suspended->suspender); } else { @@ -5394,8 +5429,8 @@ static CHANSERV_FUNC(cmd_csuspend) spamserv_cs_suspend(channel, expiry, 1, suspended->reason); DelChannelUser(chanserv, channel, suspended->reason, 0); reply("CSMSG_SUSPENDED", channel->name); - sprintf(reason, "%s suspended by %s.", channel->name, suspended->suspender); - global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason); + global_message_args(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, "CSMSG_SUSPENDED_BY", + channel->name, suspended->suspender); } return 1; } @@ -5403,7 +5438,6 @@ static CHANSERV_FUNC(cmd_csuspend) static CHANSERV_FUNC(cmd_cunsuspend) { struct suspended *suspended; - char message[MAXLEN]; if(!IsSuspended(channel->channel_info)) { @@ -5417,8 +5451,8 @@ static CHANSERV_FUNC(cmd_cunsuspend) timeq_del(suspended->expires, chanserv_expire_suspension, suspended, 0); chanserv_expire_suspension(suspended); reply("CSMSG_UNSUSPENDED", channel->name); - sprintf(message, "%s unsuspended by %s.", channel->name, user->handle_info->handle); - global_message(MESSAGE_RECIPIENT_OPERS|MESSAGE_RECIPIENT_HELPERS, message); + global_message_args(MESSAGE_RECIPIENT_OPERS|MESSAGE_RECIPIENT_HELPERS, "CSMSG_UNSUSPENDED_BY", + channel->name, user->handle_info->handle); return 1; } @@ -5437,7 +5471,7 @@ typedef struct chanservSearch typedef void (*channel_search_func)(struct chanData *channel, void *data); static search_t -chanserv_search_create(struct userNode *user, unsigned int argc, char *argv[]) +chanserv_search_create(struct svccmd *cmd, struct userNode *user, unsigned int argc, char *argv[]) { search_t search; unsigned int i; @@ -5451,7 +5485,7 @@ chanserv_search_create(struct userNode *user, unsigned int argc, char *argv[]) /* Assume all criteria require arguments. */ if(i == (argc - 1)) { - send_message(user, chanserv, "MSG_MISSING_PARAMS", argv[i]); + reply("MSG_MISSING_PARAMS", argv[i]); goto fail; } @@ -5472,7 +5506,7 @@ chanserv_search_create(struct userNode *user, unsigned int argc, char *argv[]) search->flags |= CHANNEL_SUSPENDED; else { - send_message(user, chanserv, "CSMSG_INVALID_CFLAG", argv[i]); + reply("CSMSG_INVALID_CFLAG", argv[i]); goto fail; } } @@ -5480,7 +5514,7 @@ chanserv_search_create(struct userNode *user, unsigned int argc, char *argv[]) search->limit = strtoul(argv[++i], NULL, 10); else { - send_message(user, chanserv, "MSG_INVALID_CRITERIA", argv[i]); + reply("MSG_INVALID_CRITERIA", argv[i]); goto fail; } } @@ -5557,7 +5591,7 @@ static CHANSERV_FUNC(cmd_search) return 0; } - search = chanserv_search_create(user, argc - 2, argv + 2); + search = chanserv_search_create(cmd, user, argc - 2, argv + 2); if(!search) return 0; @@ -5638,7 +5672,7 @@ static MODCMD_FUNC(chan_opt_defaulttopic) && !match_ircglob(channel->channel_info->topic, channel->channel_info->topic_mask)) reply("CSMSG_TOPIC_MISMATCH", channel->name); } - SetChannelTopic(channel, chanserv, chanserv, topic ? topic : "", 1); + SetChannelTopic(channel, chanserv, user, topic ? topic : "", 1); } if(channel->channel_info->topic) @@ -5734,6 +5768,11 @@ static MODCMD_FUNC(chan_opt_modes) if(argc > 1) { + if (checkDefCon(DEFCON_NO_MODE_CHANGE) && !IsOper(user)) { + reply("CSMSG_DEFCON_NO_MODE_CHANGE"); + return 0; + } + if(!check_user_level(channel, user, lvlEnfModes, 1, 0)) { reply("CSMSG_NO_ACCESS"); @@ -6196,11 +6235,10 @@ static MODCMD_FUNC(user_opt_autoop) reply("CSMSG_NOT_USER", channel->name); return 0; } - if(uData->access < UL_OP /*channel->channel_info->lvlOpts[lvlGiveOps]*/) + if(uData->access < UL_HALFOP /*channel->channel_info->lvlOpts[lvlGiveOps]*/) return user_binary_option("CSMSG_USET_AUTOVOICE", USER_AUTO_OP, CSFUNC_ARGS); else return user_binary_option("CSMSG_USET_AUTOOP", USER_AUTO_OP, CSFUNC_ARGS); - /* TODO: add halfops error message? or is the op one generic enough? */ } static MODCMD_FUNC(user_opt_autoinvite) @@ -6208,6 +6246,11 @@ static MODCMD_FUNC(user_opt_autoinvite) return user_binary_option("CSMSG_USET_AUTOINVITE", USER_AUTO_INVITE, CSFUNC_ARGS); } +static MODCMD_FUNC(user_opt_autojoin) +{ + return user_binary_option("CSMSG_USET_AUTOJOIN", USER_AUTO_JOIN, CSFUNC_ARGS); +} + static MODCMD_FUNC(user_opt_info) { struct userData *uData; @@ -6266,7 +6309,7 @@ static CHANSERV_FUNC(cmd_uset) { char *options[] = { - "AutoOp", "AutoInvite", "Info" + "AutoOp", "AutoInvite", "AutoJoin", "Info" }; if(!uset_shows_list.size) @@ -6317,7 +6360,7 @@ static CHANSERV_FUNC(cmd_giveownership) struct giveownership *giveownership; unsigned int force, override; unsigned short co_access, new_owner_old_access; - char reason[MAXLEN], transfer_reason[MAXLEN]; + char transfer_reason[MAXLEN]; REQUIRE_PARAMS(2); curr_user = GetChannelAccess(cData, user->handle_info); @@ -6355,6 +6398,10 @@ static CHANSERV_FUNC(cmd_giveownership) reply("CSMSG_TRANSFER_WAIT", delay, channel->name); return 0; } + if (!curr_user) { + reply("CSMSG_NO_OWNER", channel->name); + return 0; + } if(!(new_owner_hi = modcmd_get_handle_info(user, argv[1]))) return 0; if(new_owner_hi == user->handle_info) @@ -6417,8 +6464,8 @@ static CHANSERV_FUNC(cmd_giveownership) channel->channel_info->giveownership = giveownership; reply("CSMSG_OWNERSHIP_GIVEN", channel->name, new_owner_hi->handle); - sprintf(reason, "%s ownership transferred to %s by %s.", channel->name, new_owner_hi->handle, user->handle_info->handle); - global_message(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, reason); + global_message_args(MESSAGE_RECIPIENT_OPERS | MESSAGE_RECIPIENT_HELPERS, "CSMSG_OWNERSHIP_TRANSFERRED", + channel->name, new_owner_hi->handle, user->handle_info->handle); return 1; } @@ -6901,6 +6948,19 @@ static CHANSERV_FUNC(cmd_calc) return 1; } +static CHANSERV_FUNC(cmd_reply) +{ + + REQUIRE_PARAMS(2); + unsplit_string(argv + 1, argc - 1, NULL); + + if(channel) + send_channel_message(channel, cmd->parent->bot, "$b%s$b: %s", user->nick, unsplit_string(argv + 1, argc - 1, NULL)); + else + send_message_type(4, user, cmd->parent->bot, "%s", unsplit_string(argv + 1, argc - 1, NULL)); + return 1; +} + static void chanserv_adjust_limit(void *data) { @@ -7082,7 +7142,11 @@ handle_join(struct modeNode *mNode) /* non users getting automodes are handled above. */ if(IsUserAutoOp(uData) && cData->chOpts[chAutomode] != 'n') { - if(uData->access >= UL_OP ) + /* just op everyone with access */ + if(uData->access >= UL_PEON && cData->chOpts[chAutomode] == 'l') + modes |= MODE_VOICE; + /* or do their access level */ + else if(uData->access >= UL_OP ) modes |= MODE_CHANOP; else if(uData->access >= UL_HALFOP ) modes |= MODE_HALFOP; @@ -7158,6 +7222,14 @@ handle_auth(struct userNode *user, UNUSED_ARG(struct handle_info *old_handle)) && !self->burst && !user->uplink->burst) irc_invite(chanserv, user, cn); + + if(!IsUserSuspended(channel) + && IsUserAutoJoin(channel) + && (channel->access >= channel->channel->lvlOpts[lvlInviteMe]) + && !self->burst + && !user->uplink->burst) + irc_svsjoin(chanserv, user, cn); + continue; } @@ -7320,12 +7392,12 @@ handle_topic(struct userNode *user, struct chanNode *channel, const char *old_to conform_topic(cData->topic_mask, channel->topic, new_topic); if(*new_topic) { - SetChannelTopic(channel, chanserv, chanserv, new_topic, 1); + SetChannelTopic(channel, chanserv, user, new_topic, 1); /* and fall through to topicsnarf code below.. */ } else /* Topic couldnt fit into mask, was too long */ { - SetChannelTopic(channel, chanserv, chanserv, old_topic, 1); + SetChannelTopic(channel, chanserv, user, old_topic, 1); send_message(user, chanserv, "CSMSG_TOPICMASK_CONFLICT1", channel->name, cData->topic_mask); send_message(user, chanserv, "CSMSG_TOPICMASK_CONFLICT2", TOPICLEN); return 1; @@ -7383,7 +7455,7 @@ handle_mode(struct chanNode *channel, struct userNode *user, const struct mod_ch else if(change->args[ii].mode & MODE_CHANOP) { const struct userNode *victim = change->args[ii].u.member->user; - if(IsService(victim) || validate_op(user, channel, (struct userNode*)victim)) + if(IsService(victim) || validate_op(NULL, user, channel, (struct userNode*)victim)) continue; if(!bounce) bounce = mod_chanmode_alloc(change->argc + 1 - ii); @@ -8542,6 +8614,7 @@ init_chanserv(const char *nick) DEFINE_COMMAND(d, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL); DEFINE_COMMAND(huggle, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL); DEFINE_COMMAND(calc, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL); + DEFINE_COMMAND(reply, 1, 0, "flags", "+nolog,+toy,+acceptchan", NULL); /* Channel options */ DEFINE_CHANNEL_OPTION(defaulttopic); @@ -8576,6 +8649,7 @@ init_chanserv(const char *nick) /* User options */ DEFINE_USER_OPTION(autoinvite); + DEFINE_USER_OPTION(autojoin); DEFINE_USER_OPTION(info); DEFINE_USER_OPTION(autoop);