Beispiel #1
0
    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))
Beispiel #2
0
    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))
Beispiel #3
0
    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))
Beispiel #4
0
    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))
Beispiel #5
0
    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()
Beispiel #8
0
    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()
Beispiel #10
0
    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)
Beispiel #12
0
    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()
Beispiel #16
0
    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)
Beispiel #17
0
    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))
Beispiel #18
0
    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))
Beispiel #19
0
    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
Beispiel #21
0
    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)
Beispiel #24
0
    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)
Beispiel #25
0
 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))
Beispiel #27
0
    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))
Beispiel #28
0
 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))
Beispiel #29
0
    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)