def topic(self, session_id, msgid): info = self.__get_group__(session_id) if info.topic: self.broker.deliver(session_id, ltd.encode_co_output("The topic is: %s" % info.topic, msgid)) else: self.broker.deliver(session_id, ltd.encode_co_output("The topic is not set.", msgid))
def whereis(self, session_id, nick, mode="", msgid=""): loggedin_session = self.session.find_nick(nick) if loggedin_session: state = self.session.get(loggedin_session) if mode == "a": status_flags = UserStatus().get_flags(state) status = " (%s)" % ", ".join( status_flags) if status_flags else "" self.broker.deliver( session_id, ltd.encode_co_output( "%-16s %s (%s)%s %s" % (nick, state.address, state.ip, status, state.t_recv.elapsed_str()), msgid)) if state.away: self.broker.deliver( session_id, ltd.encode_co_output( "Away: %s since %s" % (state.away, state.t_away.elapsed_str()), msgid)) else: self.broker.deliver( session_id, ltd.encode_co_output( "%-16s %s (%s) %s" % (nick, state.address, state.ip, state.t_recv.elapsed_str()), msgid)) else: self.broker.deliver(session_id, ltd.encode_co_output("User not found.", msgid))
def __send__wrapped__(self, session_id, prefix, seq, msgid): line = ", ".join(seq) if line: parts = wrap(line, 64) self.broker.deliver(session_id, ltd.encode_co_output("%s%s" % (prefix, parts[0]), msgid)) for part in parts[1:]: self.broker.deliver(session_id, ltd.encode_co_output("%s%s" % (" " * len(prefix), part), msgid))
def news_item(self, session_id, news_item, msgid=""): item = self.__news.get_item(news_item) if not item: raise LtdStatusException("News", "Entry not found.") self.broker.deliver(session_id, ltd.encode_co_output("-" * 64, msgid)) for line in item: self.broker.deliver(session_id, ltd.encode_co_output(line, msgid)) self.broker.deliver(session_id, ltd.encode_co_output("-" * 64, msgid))
def all_news(self, session_id, msgid=""): news = self.__news.all() if not news: raise LtdStatusException("News", "No news.") self.broker.deliver(session_id, ltd.encode_co_output("-" * 64, msgid)) for item in news: for line in item: self.broker.deliver(session_id, ltd.encode_co_output(line, msgid)) self.broker.deliver(session_id, ltd.encode_co_output("-" * 64, msgid))
def set_protected(self, session_id, protected, msgid=""): state = self.session.get(session_id) if not state.authenticated: raise LtdErrorException("You must be registered to change your protection level.") with self.nickdb_connection.enter_scope() as scope: self.nickdb.set_protected(scope, state.nick, protected) if protected: self.broker.deliver(session_id, ltd.encode_co_output("Protection enabled.", msgid)) else: self.broker.deliver(session_id, ltd.encode_co_output("Protection disabled.", msgid)) scope.complete()
def set_security_mode(self, session_id, enabled, msgid=""): state = self.session.get(session_id) if not state.authenticated: raise LtdErrorException("You must be registered to change your security.") with self.nickdb_connection.enter_scope() as scope: self.nickdb.set_secure(scope, state.nick, enabled) if enabled: self.broker.deliver(session_id, ltd.encode_co_output("Security set to password required.", msgid)) else: self.broker.deliver(session_id, ltd.encode_co_output("Security set to automatic.", msgid)) scope.complete()
def __show_short_group__(self, session_id, state, info, logins, is_admin, with_members, msgid): show_group = True display_name = str(info) if info.visibility != group.Visibility.VISIBLE: if is_admin or state.group == info.key: display_name = "*%s*" % str(info) else: display_name = "-SECRET-" show_group = info.visibility != group.Visibility.INVISIBLE if show_group: moderator = logins[ info.moderator].nick if info.moderator else "(None)" flags = "%s%s%s" % (chr( info.control.value), chr( info.visibility.value), chr(info.volume.value)) topic = info.topic if info.topic else "(None)" self.broker.deliver( session_id, ltd.encode_co_output( "Group: %-12s (%s) Mod: %-12s Topic: %s" % (display_name, flags, moderator, topic), msgid)) if with_members: subscribers = ", ".join( sorted([ logins[sub_id].nick for sub_id in self.broker.get_subscribers(info.key) ], key=lambda n: n.lower())) lines = wrap(subscribers, 64) if lines: self.broker.deliver( session_id, ltd.encode_co_output(" Members: %s" % lines[0], msgid)) for line in lines[1:]: self.broker.deliver( session_id, ltd.encode_co_output(" %s" % line, msgid)) return show_group
def request_confirmation(self, session_id): self.log.debug("Requesting email confirmation.") nick, details = self.__load_details_if_confirmed__(session_id) code = None with self.confirmation_connection.enter_scope() as scope: pending = self.confirmation.count_pending_requests(scope, nick, details.email, self.config.timeouts_confirmation_request) if pending > 0: self.reputation.warning(session_id) raise LtdStatusException("Confirmation", "Confirmation request pending, please check your inbox.") code = self.confirmation.create_request(scope, nick, details.email) scope.complete() self.log.debug("Confirmation code generated: %s", code) with self.mail_sink_connection.enter_scope() as scope: text = self.template.load("confirm_email") tpl = Template(text) body = tpl.substitute(nick=nick, code=code) self.mail_sink.put(scope, details.email, "Email confirmation", body) self.broker.deliver(session_id, ltd.encode_co_output("Confirmation mail sent.")) scope.complete()
def read_messages(self, session_id, msgid=""): state = self.session.get(session_id) if not state.authenticated: raise LtdErrorException( "You must be registered to read any messages.") with self.nickdb_connection.enter_scope() as scope: if self.nickdb.count_messages(scope, state.nick) == 0: raise LtdErrorException("No messages.") for msg in self.nickdb.get_messages(scope, state.nick): self.broker.deliver( session_id, ltd.encode_co_output( "Message left at %s (UTC)." % msg.date, msgid)) e = ltd.Encoder("c") e.add_field_str(msg.sender, append_null=False) e.add_field_str(msg.text, append_null=True) self.broker.deliver(session_id, e.encode()) self.nickdb.delete_message(scope, msg.uuid) scope.complete() self.__notification_table.remove_entry(session_id, "mbox_full")
def display_avatar(self, session_id, nick, msgid=""): if not nick: raise LtdErrorException("Usage: /whois {nick}") with self.nickdb_connection.enter_scope() as scope: if not self.nickdb.exists(scope, nick): raise LtdErrorException("%s not found." % nick) details = self.nickdb.lookup(scope, nick) if not details.avatar: raise LtdErrorException("%s has no avatar." % nick) with self.avatar_connection.enter_scope() as scope: key = self.avatar_reader.lookup_key(scope, nick) if not key: raise LtdErrorException("Preview not available.") lines = self.avatar_storage.load(key) if not lines: raise LtdErrorException("Preview not available.") msgs = bytearray() for l in lines: msgs.extend(ltd.encode_co_output(l, msgid)) self.broker.deliver(session_id, msgs)
def receive(self, session_id, msgid=""): try: for line in self.__motd.read(): self.broker.deliver(session_id, ltd.encode_co_output(line, msgid)) except: self.log.warning(traceback.format_exc())
def enable_forwarding(self, session_id, enabled, msgid=""): state = self.session.get(session_id) if not state.authenticated: raise LtdErrorException("You must be registered to change forwarding.") with self.nickdb_connection.enter_scope() as scope: if not self.nickdb.is_email_confirmed(scope, state.nick): raise LtdErrorException("Please confirm your email address first.") self.nickdb.enable_message_forwarding(scope, state.nick, enabled) if enabled: self.broker.deliver(session_id, ltd.encode_co_output("Message forwarding enabled.", msgid)) else: self.broker.deliver(session_id, ltd.encode_co_output("Message forwarding disabled.", msgid)) scope.complete()
def reset_password(self, session_id, email): self.log.debug("Resetting user password.") if not email: raise LtdErrorException("Usage: /newpasswd {confirmed email address}") if not validate.is_valid_email(email): raise LtdErrorException("Wrong email address.") state = self.session.get(session_id) details = None with self.nickdb_connection.enter_scope() as scope: if not self.nickdb.exists(scope, state.nick): self.reputation.warning(session_id) raise LtdErrorException("Nick not registered.") if not self.nickdb.is_email_confirmed(scope, state.nick): self.reputation.warning(session_id) raise LtdErrorException("Wrong email address.") details = self.nickdb.lookup(scope, state.nick) if details.email.lower() != email.lower(): self.reputation.critical(session_id) raise LtdErrorException("Wrong email address.") code = None with self.password_reset_connection.enter_scope() as scope: pending = self.password_reset.count_pending_requests(scope, state.nick, self.config.timeouts_password_reset_request) if pending > 0: self.reputation.critical(session_id) raise LtdStatusException("Pass", "Password reset pending, please check your inbox.") code = self.password_reset.create_request(scope, state.nick) scope.complete() self.log.debug("Reset code generated: %s", code) with self.mail_sink_connection.enter_scope() as scope: text = self.template.load("password_reset_email") tpl = Template(text) body = tpl.substitute(nick=state.nick, code=code) self.mail_sink.put(scope, details.email, "Password reset", body) self.broker.deliver(session_id, ltd.encode_co_output("Email sent.")) scope.complete()
def change_field(self, session_id, field, text, msgid=""): state = self.session.get(session_id) if not state.authenticated: raise LtdErrorException("You must be registered to change your profile.") if not self.__validate_field__(field, text): raise LtdResponseException("Invalid attribute.", ltd.encode_co_output("'%s' format not valid." % self.__map_field__(field), msgid)) with self.nickdb_connection.enter_scope() as scope: details = self.nickdb.lookup(scope, state.nick) old_val = getattr(details, field) if not old_val: old_val = "" setattr(details, field, text) self.nickdb.update(scope, state.nick, details) if text: self.broker.deliver(session_id, ltd.encode_co_output("%s set to '%s'." % (self.__map_field__(field), text), msgid)) else: self.broker.deliver(session_id, ltd.encode_co_output("%s unset." % self.__map_field__(field), msgid)) if field == "email" and old_val.lower() != text.lower() and self.nickdb.is_email_confirmed(scope, state.nick): self.broker.deliver(session_id, ltd.encode_co_output("Email confirmation revoked.", msgid)) self.nickdb.set_email_confirmed(scope, state.nick, False) self.nickdb.enable_message_forwarding(scope, state.nick, False) scope.complete() if field == "avatar": with self.avatar_connection.enter_scope() as scope: if text: self.avatar_writer.put(scope, state.nick, text) else: self.avatar_writer.clear(scope, state.nick) scope.complete()
def status(self, session_id, msgid): info = self.__get_group__(session_id) logins = self.session.get_nicks() self.broker.deliver(session_id, ltd.encode_co_output("Name: %s Mod: %s (%s / %s / %s)" % (str(info), logins[info.moderator].nick if info.moderator else "(None)", info.visibility, info.control, info.volume), msgid)) self.broker.deliver(session_id, ltd.encode_co_output("Size: %s" % info.group_limit_str, msgid)) self.broker.deliver(session_id, ltd.encode_co_output("Idle-Boot: %s" % info.idle_boot_str, msgid)) self.broker.deliver(session_id, ltd.encode_co_output("Idle-Mod: %s" % info.idle_mod_str, msgid)) self.__send__wrapped__(session_id, "Nicks invited: ", info.invited_nicks, msgid) self.__send__wrapped__(session_id, "Addresses invited: ", info.invited_addresses, msgid) self.__send__wrapped__(session_id, "Talkers: ", info.talker_nicks, msgid) self.__send__wrapped__(session_id, "Talkers (addresses) ", info.talker_addresses, msgid)
def __show_summary__(self, session_id, logins, groups, msgid): logins_n = len(logins) - 1 logins_suffix = "" if logins_n == 1 else "s" groups_n = len(groups) groups_suffix = "" if groups_n == 1 else "s" self.broker.deliver( session_id, ltd.encode_co_output( "Total: %d user%s in %d group%s." % (logins_n, logins_suffix, groups_n, groups_suffix), msgid))
def get_reputation(self, session_id, nick, msgid=""): loggedin_session = self.session.find_nick(nick) if not loggedin_session: raise LtdErrorException("%s is not signed on." % nick) loggedin_state = self.session.get(loggedin_session) reputation = self.reputation.get(loggedin_session) self.broker.deliver(session_id, ltd.encode_co_output("%s (%s): %.2f" % (nick, loggedin_state.address, reputation), msgid))
def set_log_level(self, session_id, level, msgid): try: verbosity = Verbosity(level) except ValueError: raise LtdErrorException("Unsupported log level: %d" % level) self.log.info("Verbosity set to %s.", verbosity) for l in self.__registry.loggers: l.setLevel(log.LOG_LEVELS[verbosity]) self.broker.deliver(session_id, ltd.encode_co_output("The log level is %d." % level, msgid))
def __load_details_if_confirmed__(self, session_id): state = self.session.get(session_id) if not state.authenticated: raise LtdErrorException("You must be registered to confirm your email address.") with self.nickdb_connection.enter_scope() as scope: if self.nickdb.is_email_confirmed(scope, state.nick): raise LtdResponseException("Already already confirmed.", ltd.encode_co_output("Email address already confirmed.")) details = self.nickdb.lookup(scope, state.nick) if not details.email: raise LtdStatusException("Confirmation", "No email address set.") return state.nick, details
def beep(self, session_id, receiver): loggedin_session = self.session.find_nick(receiver) if not loggedin_session: raise LtdErrorException("%s is not signed on." % receiver) loggedin_state = self.session.get(loggedin_session) state = self.session.get(session_id) if state.echo == session.EchoMode.VERBOSE: self.broker.deliver( session_id, ltd.encode_co_output("<*to: %s*> [=Beep=]" % receiver)) if loggedin_state.beep != session.BeepMode.ON: if loggedin_state.beep == session.BeepMode.VERBOSE: self.broker.deliver( loggedin_session, ltd.encode_status_msg( "No-Beep", "%s attempted (and failed) to beep you." % state.nick)) raise LtdStatusException("Beep", "User has nobeep enabled.") self.broker.deliver(loggedin_session, ltd.encode_str("k", state.nick)) if loggedin_state.away: if not self.away_table.is_alive(session_id, receiver): self.broker.deliver( session_id, ltd.encode_status_msg( "Away", "%s (since %s)." % (loggedin_state.away, loggedin_state.t_away.elapsed_str()))) self.away_table.set_alive(session_id, receiver, self.config.timeouts_away_message)
def delete(self, session_id, password, msgid=""): state = self.session.get(session_id) if not state.authenticated: raise LtdErrorException("You must be registered to delete your entry.") if not password: raise LtdErrorException("Usage: /delete {password}") if state.nick.lower() == core.ADMIN.lower(): raise LtdErrorException("Cannot delete default admin account.") with self.nickdb_connection.enter_scope() as scope: if not self.nickdb.check_password(scope, state.nick, password): raise LtdErrorException("Password incorrect.") self.nickdb.delete(scope, state.nick) self.broker.deliver(session_id, ltd.encode_co_output("Record deleted.", msgid)) self.session.update(session_id, authentication=False) scope.complete()
def send(self, session_id, receiver, message): loggedin_session = self.session.find_nick(receiver) if loggedin_session: state = self.session.get(session_id) max_len = 254 - validate.NICK_MAX - 5 for part in wrap(message, max_len): e = ltd.Encoder("c") e.add_field_str(state.nick, append_null=False) e.add_field_str(part, append_null=True) self.broker.deliver(loggedin_session, e.encode()) if state.echo == session.EchoMode.VERBOSE: self.broker.deliver( session_id, ltd.encode_co_output("<*to: %s*> %s" % (receiver, part))) loggedin_state = self.session.get(loggedin_session) if loggedin_state.away: if not self.__away_table.is_alive(session_id, receiver): self.broker.deliver( session_id, ltd.encode_status_msg( "Away", "%s (since %s)." % (loggedin_state.away, loggedin_state.t_away.elapsed_str()))) self.__away_table.set_alive( session_id, receiver, self.config.timeouts_away_message) else: raise LtdErrorException("%s is not signed on." % receiver)
def list(self, session_id, msgid=""): is_admin = False state = self.session.get(session_id) if state.authenticated: with self.nickdb_connection.enter_scope() as scope: is_admin = self.nickdb.is_admin(scope, state.nick) logins = self.session.get_nicks() available_groups = self.groups.get_groups() if available_groups: for info in available_groups[:-1]: if self.__show_group__(session_id, state, info, logins, is_admin, False, msgid): self.broker.deliver(session_id, ltd.encode_co_output("", msgid)) self.__show_group__(session_id, state, available_groups[-1], logins, is_admin, False, msgid) self.__show_summary__(session_id, logins, available_groups, msgid)
def __send_contents__(self, session_id, contents, msgid): for line in contents.split("\n")[:-1]: self.broker.deliver(session_id, ltd.encode_co_output(line, msgid))
def whoami(self, session_id, msgid=""): state = self.session.get(session_id) self.broker.deliver(session_id, ltd.encode_co_output(state.nick, msgid))
def log_level(self, session_id, msgid): verbosity = next(k for k, v in log.LOG_LEVELS.items() if v == self.log.level) self.broker.deliver(session_id, ltd.encode_co_output("The log level is %d." % verbosity.value, msgid))
def version(self, session_id, msgid=""): self.broker.deliver(session_id, ltd.encode_co_output("%s v%s" % (core.NAME, core.VERSION), msgid)) self.broker.deliver(session_id, ltd.encode_co_output("Protocol Level: %d Max Users: %d" % (core.PROTOCOL_LEVEL, self.config.server_max_logins), msgid))
def stats(self, session_id, timeframe="s", msgid=""): nickserv_id = self.session.find_nick(core.NICKSERV) nickserv_state = self.session.get(nickserv_id) stats = None description = None with self.statsdb_connection.enter_scope() as scope: if timeframe == "s": stats = self.statsdb.start(scope) description = "since start" elif timeframe == "t": stats = self.statsdb.today(scope) description = "today" elif timeframe == "m": stats = self.statsdb.month(scope) description = "this month" elif timeframe == "y": stats = self.statsdb.year(scope) description = "this year" elif timeframe == "a": stats = self.statsdb.all(scope) description = "overall" users_n = self.session.count_logins() groups_n = len(self.groups) away_n = len([kv for kv in self.session if kv[1].away]) user_args = [users_n, "" if users_n == 1 else "s", groups_n, "" if groups_n == 1 else "s", away_n, "" if away_n == 1 else "s"] self.broker.deliver(session_id, ltd.encode_co_output("Server Settings:", msgid)) self.broker.deliver(session_id, ltd.encode_co_output(" Version: %s v%s" % (core.NAME, core.VERSION), msgid)) self.broker.deliver(session_id, ltd.encode_co_output(" Protocol Level: %d, Max Users: %d" % (core.PROTOCOL_LEVEL, self.config.server_max_logins), msgid)) self.broker.deliver(session_id, ltd.encode_co_output("", msgid)) self.broker.deliver(session_id, ltd.encode_co_output("General:", msgid)) self.broker.deliver(session_id, ltd.encode_co_output(" Started: %s (UTC)" % nickserv_state.signon, msgid)) self.broker.deliver(session_id, ltd.encode_co_output(" Logins: %d user%s in %d group%s (%d away user%s)" % tuple(user_args), msgid)) self.broker.deliver(session_id, ltd.encode_co_output("", msgid)) self.broker.deliver(session_id, ltd.encode_co_output("Server Stats (%s):" % description, msgid)) self.broker.deliver(session_id, ltd.encode_co_output(" Max Logins: %d, Max Groups: %d" % (stats.max_logins, stats.max_groups), msgid)) if stats.max_idle: self.broker.deliver(session_id, ltd.encode_co_output(" Max Idle: %s (%s)" % (stats.max_idle[1], dateutils.elapsed_time(stats.max_idle[0])), msgid)) else: self.broker.deliver(session_id, ltd.encode_co_output(" Max Idle: (None)", msgid)) self.broker.deliver(session_id, ltd.encode_co_output(" Signons: %d, Boots: %d, Drops: %d" % (stats.signons, stats.boots, stats.drops), msgid)) self.broker.deliver(session_id, ltd.encode_co_output(" Idle-Boots: %d, Idle-Mod-Boots: %d" % (stats.idleboots, stats.idlemods), msgid))
def whois(self, session_id, nick, msgid=""): if not nick: raise LtdErrorException("Usage: /whois {nick}") state = self.session.get(session_id) signon = signoff = protected = details = None with self.nickdb_connection.enter_scope() as scope: if not self.nickdb.exists(scope, nick): raise LtdErrorException("%s not found." % nick) signon = self.nickdb.get_signon(scope, nick) signoff = self.nickdb.get_signoff(scope, nick) protected = self.nickdb.is_protected(scope, nick) details = self.nickdb.lookup(scope, nick) login = idle = away = None loggedin_session = self.session.find_nick(nick) if loggedin_session: loggedin_state = self.session.get(loggedin_session) login = loggedin_state.address idle = loggedin_state.t_recv.elapsed_str() if loggedin_state.away: away = "%s (since %s)" % (loggedin_state.away, loggedin_state.t_away.elapsed_str()) email = None if details.email: if (session_id == loggedin_session and state.authenticated) or not protected: email = details.email else: email = hide_chars(details.email) msgs = bytearray() def display_value(text): if not text: text = "(None)" return text msgs.extend(ltd.encode_co_output("Nickname: %-24s Address: %s" % (nick, display_value(login)), msgid)) msgs.extend(ltd.encode_co_output("Phone Number: %-24s Real Name: %s" % (display_value(details.phone), display_value(details.real_name)), msgid)) msgs.extend(ltd.encode_co_output("Last signon: %-24s Last signoff: %s" % (display_value(signon), display_value(signoff)), msgid)) if idle: msgs.extend(ltd.encode_co_output("Idle: %s" % idle, msgid)) if away: msgs.extend(ltd.encode_co_output("Away: %s" % away, msgid)) msgs.extend(ltd.encode_co_output("E-Mail: %s" % display_value(email), msgid)) msgs.extend(ltd.encode_co_output("WWW: %s" % display_value(details.www), msgid)) msgs.extend(ltd.encode_co_output("Avatar: %s" % display_value(details.avatar), msgid)) if not details.address: msgs.extend(ltd.encode_co_output("Street address: (None)", msgid)) else: parts = [p.strip() for p in details.address.split("|")] msgs.extend(ltd.encode_co_output("Street address: %s" % parts[0], msgid)) for part in parts[1:]: msgs.extend(ltd.encode_co_output(" %s" % part, msgid)) if not details.text: msgs.extend(ltd.encode_co_output("Text: (None)", msgid)) else: parts = wrap(details.text, 64) msgs.extend(ltd.encode_co_output("Text: %s" % parts[0], msgid)) for part in parts[1:]: msgs.extend(ltd.encode_co_output(" %s" % part, msgid)) self.broker.deliver(session_id, msgs)