diff options
-rw-r--r-- | CHANGELOG | 13 | ||||
-rw-r--r-- | README | 29 | ||||
-rw-r--r-- | data/default_config.cfg | 11 | ||||
-rw-r--r-- | data/poezio.1 | 7 | ||||
-rw-r--r-- | launch.sh | 1 | ||||
-rw-r--r-- | src/buffers.py (renamed from src/window.py) | 8 | ||||
-rw-r--r-- | src/contact.py | 14 | ||||
-rw-r--r-- | src/core.py | 4 | ||||
-rw-r--r-- | src/handler.py | 83 | ||||
-rw-r--r-- | src/logger.py | 26 | ||||
-rw-r--r-- | src/message.py | 4 | ||||
-rw-r--r-- | src/multiuserchat.py | 2 | ||||
-rw-r--r-- | src/singleton.py | 23 | ||||
-rw-r--r-- | src/tab.py | 70 | ||||
-rw-r--r-- | src/text_buffer.py | 4 | ||||
-rw-r--r-- | src/user.py | 6 |
16 files changed, 100 insertions, 205 deletions
@@ -3,15 +3,20 @@ For more detailed changelog, see the roadmap: http://codingteam.net/project/poezio/roadmap * Poezio 0.7 - dev -"Complete the MUC support" -- All poezio colors can be changed with a theme file -- /say command +"Roster" +- Introduce the roster +- One to one conversations +- Roster search +- Resizable mini-buffer displaying various informations +- All colors can be changed with a theme file +- /say and // commands - Warn user about publicly logged rooms - Possibility to limit the number of history messages received from MUC - auto-rejoin when kicked from a MUC - The number of lines available to scroll down is displayed - Possibility to use a modified nickname automatically when a nick is reserved -- A line indicates the new messages in the window +- A line separates the alread-read messages + from the new messages in a conversation - Information messages are more colored - bugfixes @@ -10,24 +10,27 @@ Homepage: http://poezio.eu Forge Page: http://codingteam.net/projet/poezio -Poezio is a console Jabber/XMPP client. Its goal is to use anonymous +Poezio is a console Jabber/XMPP client. Its goal is to use anonymous connections to simply let the user join MultiUserChats. This way, the user doesn't have to create a Jabber account, exactly like people are using -IRC. Poezio's commands are designed to be (if possible) like IRC +IRC. Poezio's commands are designed to be (if possible) like IRC clients (weechat, irssi, etc). Since version 0.7, poezio can handle real Jabber accounts along with -roster and one to one conversation, making it a full-featured console +roster and one to one conversations, making it a full-featured console Jabber client, but still MultiUserChats-centered. +In the futur, poezio should implement at a 100% level all XEP related to +MUCs, especially XEP 0045. +All other IM-related XEP (wherever possible) should be implemented through +plugins or directly in poezio's core. ======================= Install ======================= You need python 3.0 or higher, and the SleekXMPP python library. -You can find my patched version at http://github.com/louiz/SleekXMPP until -my changes (required to properly run poezio) are merged upstream. +SleekXMPP can be found at http://github.com/fritzy/SleekXMPP. you can launch poezio with -sh launch.sh +./launch.sh or you can install it with (as root or with sudo) make install @@ -36,7 +39,7 @@ you can now simply launch `poezio' You can edit the config file (~/.config/poezio/poezio.cfg by default) or data/default_config.cfg (if you want to edit the config before the -first launch) +first launch). The default config file is fully commented. Please, see the online documentation for more information on installing, configuring or using poezio: @@ -66,10 +69,10 @@ Report a bug: http://codingteam.net/project/poezio/bugs/add Poezio is Free Software. (learn more: http://www.gnu.org/philosophy/free-sw.html) -Poezio is released under the Gnu GPLv3 license -Please read the COPYING file for details +Poezio is released under the Gnu GPLv3 license. +Please read the COPYING file for details. -The artwork logo is made by Gaëtan Ribémont and released under +The artwork logo was made by Gaëtan Ribémont and released under the Creative Commons BY license (http://creativecommons.org/licenses/by/2.0/) ======================= @@ -85,9 +88,3 @@ the Creative Commons BY license (http://creativecommons.org/licenses/by/2.0/) FlashCode (weechat dev) - Useful advices on how to use ncurses efficiently = Project = Gajim - send_vcard method and common.py - -======================= - Donate -======================= -If you're willing to thank me, or ask for an on-demand feature, please -see the page http://louiz.org/donate.html and contact me. diff --git a/data/default_config.cfg b/data/default_config.cfg index 5d1ddd5e..aaa607b2 100644 --- a/data/default_config.cfg +++ b/data/default_config.cfg @@ -17,7 +17,7 @@ port = 5222 resource = # the nick you will use when joining a room with no associated nick -# If this is empty, the $USER variable will be used +# If this is empty, the $USER environn<ement variable will be used default_nick = # Jabber identifiant. Specify it only if you want to connect using an existing @@ -35,15 +35,6 @@ password = # default_nick will be used if "/nickname" is not specified rooms = poezio@conference.codingteam.net -# PROXY -# set to true if you want to use an http proxy server -# if false, no proxy will be used and the proxy_* settings will have no effect -use_proxy = false -proxy_server = -proxy_port = -proxy_user = -proxy_password = - # the completion type you will use to complete nicknames # if "normal", complete the entire name to the first available completion # and then cycle through the possible completion with the next TABs diff --git a/data/poezio.1 b/data/poezio.1 index b5830a91..58d03a89 100644 --- a/data/poezio.1 +++ b/data/poezio.1 @@ -5,7 +5,7 @@ .SH "NAME" Poezio \- a ncurses jabber client .SH "SYNOPSIS" -.B poezio [\-f \fICONFIG_FILE\fR] [\-h] +.B poezio [\-f \fICONFIG_FILE\fR] [\-d \fIDEBUG_FILE\fR] [\-h] .SH "DESCRIPTION" .B Poezio is a console jabber (XMPP) client written in Python and using ncurses to draw its interface. It aims at being similar to the most famous IRC clients. For more information on XMPP see http://xmpp.org and on Poezio see http://poezio.eu @@ -15,10 +15,13 @@ is a console jabber (XMPP) client written in Python and using ncurses to draw it \fB\-f\fR, \fB\-\-file \fICONFIG_FILE\fR Run poezio using \fICONFIG_FILE\fR as the config file instead of ~/.config/poezio/poezio.cfg .TP +\fB\-d\fR, \fB\-\-debug \fIDEBUG_FILE\fR +Log debug from both poezio and SleekXMPP in \fIDEBUG_FILE\fR. Debug contains incoming and outgoing stanzas in addition to various message helping poezio's debuging. +.TP \fB\-h\fR Display and help message .SH "BUGS" -Sure, of course. +Sure. .SH "FEEDBACK" You are encouraged to report bugs or feature requests on http://codingteam.net/project/poezio. You can also find us on the Jabber chatroom poezio@conference.codingteam.net @@ -1,4 +1,3 @@ #!/usr/bin/env sh python3 src/poezio.py "$@" - diff --git a/src/window.py b/src/buffers.py index db8d2822..d4af680d 100644 --- a/src/window.py +++ b/src/buffers.py @@ -14,6 +14,14 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see <http://www.gnu.org/licenses/>. +""" +Define all the buffers. +A buffer is a little part of the screen, for example the input buffer, +the text bufferr, the roster buffer, etc. +A Tab (see tab.py) is composed of multiple Buffers +A buffer can also be called Window, even if it's not prefered. +""" + from gettext import (bindtextdomain, textdomain, bind_textdomain_codeset, gettext as _) from os.path import isfile diff --git a/src/contact.py b/src/contact.py index 1eb41f72..8341d4b8 100644 --- a/src/contact.py +++ b/src/contact.py @@ -15,12 +15,15 @@ # along with Poezio. If not, see <http://www.gnu.org/licenses/>. """ -Defines the Resource and Contact classes +Defines the Resource and Contact classes, which are used in +the roster """ -from sleekxmpp.xmlstream.stanzabase import JID + import logging log = logging.getLogger(__name__) +from sleekxmpp.xmlstream.stanzabase import JID + class Resource(object): """ Defines a roster item. @@ -80,8 +83,7 @@ class Contact(object): def get_highest_priority_resource(self): """ - There must be, at any time, at least ONE resource. - And they always should be ordered by priority. + Return the resource with the highest priority """ ret = None for resource in self._resources: @@ -94,8 +96,10 @@ class Contact(object): Called, for example, when a new resource get offline (the first, or any subsequent one) """ - # TODO sort by priority + def f(o): + return o.get_priority() self._resources.append(resource) + self._resources = sorted(self._resources, key=f, reverse=True) def remove_resource(self, resource): """ diff --git a/src/core.py b/src/core.py index 40d727b4..ce271613 100644 --- a/src/core.py +++ b/src/core.py @@ -38,9 +38,9 @@ log = logging.getLogger(__name__) import multiuserchat as muc from connection import connection -from handler import Handler from config import config from tab import MucTab, InfoTab, PrivateTab, RosterInfoTab, ConversationTab +from logger import logger from user import User from room import Room from roster import Roster, RosterGroup, roster @@ -822,6 +822,8 @@ class Core(object): body = message['body'] if body: date = date if delayed == True else None + if not delayed: + logger.groupchat(room_from, nick_from, body) self.add_message_to_text_buffer(room, body, date, nick_from) self.refresh_window() self.doupdate() diff --git a/src/handler.py b/src/handler.py deleted file mode 100644 index 350ea0ed..00000000 --- a/src/handler.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2009, 2010 Erwan Briand -# Copyright 2010, Florent Le Coz <louiz@louiz.org> - -# This program 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 version 3 of the License. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# 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, see <http://www.gnu.org/licenses/>. - -from singleton import Singleton - -#Todo, it's not a singleton. Oh, also, remove-me - -class Handler(Singleton): - """ - This class is the global handler for the software's signals. - """ - __is_first_instance = True - - def __init__(self): - if Handler.__is_first_instance: - Handler.__is_first_instance = False - - self.__signals__ = { - - 'on-connected': list(), - # At the end of a successful connection process. - # emitted when presence confirmation is received - # Args: jid - - 'join-room': list(), - # Join a room. - # Args: room, nick - - 'room-presence': list(), - # A presence is received - # Args: the stanza object - - 'room-message': list(), - # A message is received - # Args: the stanza object - - 'private-message': list(), - # A message is received - # Args: the stanza object - - 'room-delayed-message': list(), - # A message is received - # Args: the stanza object - - 'send-version': list(), - # We send our version - # Args: the stanza we reply to - - 'send-time': list(), - # We send our time - # Args: the stanza we reply to - - 'error-message': list(), - # We send our time - # Args: the stanza we reply to - - 'error': list() - # We send our time - # Args: the stanza we reply to - } - - def connect(self, signal, func): - """Connect a function to a signal.""" - if func not in self.__signals__[signal]: - self.__signals__[signal].append(func) - - def emit(self, signal, **kwargs): - """Emit a signal.""" - if signal in self.__signals__: - for func in self.__signals__[signal]: - func(**kwargs) diff --git a/src/logger.py b/src/logger.py index 4cfb7793..a1479f9c 100644 --- a/src/logger.py +++ b/src/logger.py @@ -29,32 +29,10 @@ class Logger(object): """ def __init__(self):# , logfile, loglevel): self.logfile = config.get('logfile', 'logs') - self.loglevel = config.get('loglevel', 3) - # self.logfile = logfile - # self.loglevel = loglevel - def info(self, msg): - if self.logfile and self.loglevel >= 3: - fd = open(self.logfile, 'a') - fd.write(datetime.now().strftime("%H:%M:%S") + ' Info [' + msg + ']\n') - fd.close() - - def warning(self, msg): - if self.logfile and self.loglevel >= 2: - fd = open(self.logfile, 'a') - fd.write(datetime.now().strftime("%H:%M:%S") + ' Warning [' + msg + ']\n') - fd.close() - - def error(self, msg): - if self.logfile and self.loglevel >= 1: - fd = open(self.logfile, 'a') - fd.write(datetime.now().strftime("%H:%M:%S") + ' Error [' + msg + ']\n') - fd.close() - sys.exit(-1) - - def message(self, room, nick, msg): + def groupchat(self, room, nick, msg): """ - log the message in the appropriate room + log the message in the appropriate room's file """ if config.get('use_log', 'false') == 'false': return diff --git a/src/message.py b/src/message.py index 07526819..6cf7a3d3 100644 --- a/src/message.py +++ b/src/message.py @@ -14,6 +14,10 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see <http://www.gnu.org/licenses/>. +""" +Define the Message class +""" + from datetime import datetime class Message(object): diff --git a/src/multiuserchat.py b/src/multiuserchat.py index 3927fc38..0fc5cb3c 100644 --- a/src/multiuserchat.py +++ b/src/multiuserchat.py @@ -46,7 +46,7 @@ def change_show(xmpp, jid, own_nick, show, status): Change our 'Show' """ pres = xmpp.makePresence(pto='%s/%s' % (jid, own_nick)) - if show: # if show is None, don't put a <show /> tag. It means "online" + if show: # if show is None, don't put a <show /> tag. It means "available" pres['type'] = show if status: pres['status'] = status diff --git a/src/singleton.py b/src/singleton.py deleted file mode 100644 index 688d20f0..00000000 --- a/src/singleton.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2009, 2010 Erwan Briand -# Copyright 2010, Florent Le Coz <louiz@louiz.org> - -# This program 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 version 3 of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# 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, see <http://www.gnu.org/licenses/>. - -class Singleton(object): - """ Canonic Singleton implementation. - """ - _instance = None - def __new__(cls, *args, **kwargs): - if cls._instance is None: - cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) - return cls._instance @@ -15,11 +15,11 @@ # along with Poezio. If not, see <http://www.gnu.org/licenses/>. """ -a Tab object is a way to organize various Window (see window.py) +a Tab object is a way to organize various Buffers (see buffers.py) around the screen at once. -A tab is then composed of multiple Window. -Each Tab object has different refresh() and resize() methods, defining of its -Window are displayed, etc +A tab is then composed of multiple Buffer. +Each Tab object has different refresh() and resize() methods, defining how its +Buffer are displayed, resized, etc """ MIN_WIDTH = 50 @@ -28,7 +28,7 @@ MIN_HEIGHT = 16 import logging log = logging.getLogger(__name__) -import window +import buffers import theme import curses import difflib @@ -145,9 +145,9 @@ class InfoTab(Tab): """ def __init__(self, stdscr, core, name): Tab.__init__(self, stdscr, core) - self.tab_win = window.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) - self.text_win = window.TextWin(self.height-2, self.width, 0, 0, stdscr, self.visible) - self.input = window.Input(1, self.width, self.height-1, 0, stdscr, self.visible) + self.tab_win = buffers.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) + self.text_win = buffers.TextWin(self.height-2, self.width, 0, 0, stdscr, self.visible) + self.input = buffers.Input(1, self.width, self.height-1, 0, stdscr, self.visible) self.name = name self.color_state = theme.COLOR_TAB_NORMAL @@ -209,14 +209,14 @@ class MucTab(Tab): """ Tab.__init__(self, stdscr, core) self._room = room - self.topic_win = window.Topic(1, self.width, 0, 0, stdscr, self.visible) - self.text_win = window.TextWin(self.height-4-self.core.information_win_size, (self.width//10)*9, 1, 0, stdscr, self.visible) - self.v_separator = window.VerticalSeparator(self.height-3, 1, 1, 9*(self.width//10), stdscr, self.visible) - self.user_win = window.UserList(self.height-3, (self.width//10), 1, 9*(self.width//10)+1, stdscr, self.visible) - self.info_header = window.MucInfoWin(1, (self.width//10)*9, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) - self.info_win = window.TextWin(self.core.information_win_size, (self.width//10)*9, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) - self.tab_win = window.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) - self.input = window.MessageInput(1, self.width, self.height-1, 0, stdscr, self.visible) + self.topic_win = buffers.Topic(1, self.width, 0, 0, stdscr, self.visible) + self.text_win = buffers.TextWin(self.height-4-self.core.information_win_size, (self.width//10)*9, 1, 0, stdscr, self.visible) + self.v_separator = buffers.VerticalSeparator(self.height-3, 1, 1, 9*(self.width//10), stdscr, self.visible) + self.user_win = buffers.UserList(self.height-3, (self.width//10), 1, 9*(self.width//10)+1, stdscr, self.visible) + self.info_header = buffers.MucInfoWin(1, (self.width//10)*9, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) + self.info_win = buffers.TextWin(self.core.information_win_size, (self.width//10)*9, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) + self.tab_win = buffers.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) + self.input = buffers.MessageInput(1, self.width, self.height-1, 0, stdscr, self.visible) def resize(self, stdscr): """ @@ -333,11 +333,11 @@ class PrivateTab(Tab): def __init__(self, stdscr, core, room): Tab.__init__(self, stdscr, core) self._room = room - self.text_win = window.TextWin(self.height-3-self.core.information_win_size, self.width, 0, 0, stdscr, self.visible) - self.info_header = window.PrivateInfoWin(1, self.width, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) - self.info_win = window.TextWin(self.core.information_win_size, self.width, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) - self.tab_win = window.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) - self.input = window.MessageInput(1, self.width, self.height-1, 0, stdscr, self.visible) + self.text_win = buffers.TextWin(self.height-3-self.core.information_win_size, self.width, 0, 0, stdscr, self.visible) + self.info_header = buffers.PrivateInfoWin(1, self.width, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) + self.info_win = buffers.TextWin(self.core.information_win_size, self.width, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) + self.tab_win = buffers.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) + self.input = buffers.MessageInput(1, self.width, self.height-1, 0, stdscr, self.visible) def resize(self, stdscr): Tab.resize(self, stdscr) @@ -420,12 +420,12 @@ class RosterInfoTab(Tab): self.name = "Roster" roster_width = self.width//2 info_width = self.width-roster_width-1 - self.v_separator = window.VerticalSeparator(self.height-2, 1, 0, roster_width, stdscr, self.visible) - self.tab_win = window.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) - self.info_win = window.TextWin(self.height-2, info_width, 0, roster_width+1, stdscr, self.visible) - self.roster_win = window.RosterWin(self.height-2-3, roster_width, 0, 0, stdscr, self.visible) - self.contact_info_win = window.ContactInfoWin(3, roster_width, self.height-2-3, 0, stdscr, self.visible) - self.default_help_message = window.HelpText(1, self.width, self.height-1, 0, stdscr, self.visible, "Enter commands with “/”. “o”: toggle offline show") + self.v_separator = buffers.VerticalSeparator(self.height-2, 1, 0, roster_width, stdscr, self.visible) + self.tab_win = buffers.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) + self.info_win = buffers.TextWin(self.height-2, info_width, 0, roster_width+1, stdscr, self.visible) + self.roster_win = buffers.RosterWin(self.height-2-3, roster_width, 0, 0, stdscr, self.visible) + self.contact_info_win = buffers.ContactInfoWin(3, roster_width, self.height-2-3, 0, stdscr, self.visible) + self.default_help_message = buffers.HelpText(1, self.width, self.height-1, 0, stdscr, self.visible, "Enter commands with “/”. “o”: toggle offline show") self.input = self.default_help_message self.set_color_state(theme.COLOR_TAB_NORMAL) @@ -491,7 +491,7 @@ class RosterInfoTab(Tab): '/' is pressed, we enter "input mode" """ curses.curs_set(1) - self.input = window.CommandInput(1, self.width, self.height-1, 0, self.default_help_message, self.visible, "", self.reset_help_message, self.execute_slash_command) + self.input = buffers.CommandInput(1, self.width, self.height-1, 0, self.default_help_message, self.visible, "", self.reset_help_message, self.execute_slash_command) self.input.do_command("/") # we add the slash def reset_help_message(self, _=None): @@ -551,7 +551,7 @@ class RosterInfoTab(Tab): in it. """ curses.curs_set(1) - self.input = window.CommandInput(1, self.width, self.height-1, 0, self.default_help_message, self.visible, "[Search]", self.on_search_terminate, self.on_search_terminate, self.set_roster_filter) + self.input = buffers.CommandInput(1, self.width, self.height-1, 0, self.default_help_message, self.visible, "[Search]", self.on_search_terminate, self.on_search_terminate, self.set_roster_filter) return True def set_roster_filter(self, txt): @@ -578,12 +578,12 @@ class ConversationTab(Tab): self._text_buffer = text_buffer self.color_state = theme.COLOR_TAB_NORMAL self._name = jid # a conversation tab is linked to one specific full jid OR bare jid - self.text_win = window.TextWin(self.height-4-self.core.information_win_size, self.width, 1, 0, stdscr, self.visible) - self.upper_bar = window.ConversationStatusMessageWin(1, self.width, 0, 0, stdscr, self.visible) - self.info_header = window.ConversationInfoWin(1, self.width, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) - self.info_win = window.TextWin(self.core.information_win_size, self.width, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) - self.tab_win = window.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) - self.input = window.MessageInput(1, self.width, self.height-1, 0, stdscr, self.visible) + self.text_win = buffers.TextWin(self.height-4-self.core.information_win_size, self.width, 1, 0, stdscr, self.visible) + self.upper_bar = buffers.ConversationStatusMessageWin(1, self.width, 0, 0, stdscr, self.visible) + self.info_header = buffers.ConversationInfoWin(1, self.width, self.height-3-self.core.information_win_size, 0, stdscr, self.visible) + self.info_win = buffers.TextWin(self.core.information_win_size, self.width, self.height-2-self.core.information_win_size, 0, stdscr, self.visible) + self.tab_win = buffers.GlobalInfoBar(1, self.width, self.height-2, 0, stdscr, self.visible) + self.input = buffers.MessageInput(1, self.width, self.height-1, 0, stdscr, self.visible) def resize(self, stdscr): Tab.resize(self, stdscr) diff --git a/src/text_buffer.py b/src/text_buffer.py index 203a966e..43bf008f 100644 --- a/src/text_buffer.py +++ b/src/text_buffer.py @@ -14,6 +14,10 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see <http://www.gnu.org/licenses/>. +""" +Define the TextBuffer class +""" + from message import Message from datetime import datetime import theme diff --git a/src/user.py b/src/user.py index eb8587f8..ba39a8fb 100644 --- a/src/user.py +++ b/src/user.py @@ -14,6 +14,11 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see <http://www.gnu.org/licenses/>. +""" +Define the user class. +An user is a MUC participant, not a roster contact (see contact.py) +""" + from random import randrange, choice from config import config from datetime import timedelta, datetime @@ -26,6 +31,7 @@ ROLE_DICT = { 'participant':2, 'moderator':3 } + class User(object): """ keep trace of an user in a Room |