# Copyright 2010-2011 Florent Le Coz # # This file is part of Poezio. # # Poezio is free software: you can redistribute it and/or modify # it under the terms of the zlib license. See the COPYING file. from gettext import gettext as _ import os import sys import time import curses import ssl from functools import reduce from hashlib import sha1 from datetime import datetime from xml.etree import cElementTree as ET import common import theming import logging import singleton import collections from sleekxmpp import JID, InvalidJID from common import safeJID from sleekxmpp.xmlstream.stanzabase import StanzaBase from sleekxmpp.xmlstream.handler import Callback log = logging.getLogger(__name__) import multiuserchat as muc import tabs import xhtml import events import pubsub import windows import connection import timed_events import bookmark from plugin_manager import PluginManager from data_forms import DataFormsTab from config import config from logger import logger from roster import roster from contact import Contact, Resource from text_buffer import TextBuffer from keyboard import read_char from theming import get_theme from fifo import Fifo from windows import g_lock from daemon import Executor # http://xmpp.org/extensions/xep-0045.html#errorstatus ERROR_AND_STATUS_CODES = { '401': _('A password is required'), '403': _('Permission denied'), '404': _('The room doesn’t exist'), '405': _('Your are not allowed to create a new room'), '406': _('A reserved nick must be used'), '407': _('You are not in the member list'), '409': _('This nickname is already in use or has been reserved'), '503': _('The maximum number of users has been reached'), } # http://xmpp.org/extensions/xep-0086.html DEPRECATED_ERRORS = { '302': _('Redirect'), '400': _('Bad request'), '401': _('Not authorized'), '402': _('Payment required'), '403': _('Forbidden'), '404': _('Not found'), '405': _('Not allowed'), '406': _('Not acceptable'), '407': _('Registration required'), '408': _('Request timeout'), '409': _('Conflict'), '500': _('Internal server error'), '501': _('Feature not implemented'), '502': _('Remote server error'), '503': _('Service unavailable'), '504': _('Remote server timeout'), '510': _('Disconnected'), } possible_show = {'available':None, 'chat':'chat', 'away':'away', 'afk':'away', 'dnd':'dnd', 'busy':'dnd', 'xa':'xa' } Status = collections.namedtuple('Status', 'show message') class Core(object): """ “Main” class of poezion """ def __init__(self): # All uncaught exception are given to this callback, instead # of being displayed on the screen and exiting the program. sys.excepthook = self.on_exception self.connection_time = time.time() self.status = Status(show=None, message='') self.running = True self.xmpp = singleton.Singleton(connection.Connection) self.xmpp.core = self roster.set_node(self.xmpp.client_roster) self.paused = False self.remote_fifo = None # a unique buffer used to store global informations # that are displayed in almost all tabs, in an # information window. self.information_buffer = TextBuffer() self.information_win_size = config.get('info_win_height', 2, 'var') self.information_win = windows.TextWin(300) self.information_buffer.add_window(self.information_win) self.tab_win = windows.GlobalInfoBar() # Number of xml tabs opened, used to avoid useless memory consumption self.xml_tabs = 0 self.xml_buffer = TextBuffer() self.tabs = [] self._current_tab_nb = 0 self.previous_tab_nb = 0 self.own_nick = config.get('default_nick', '') or self.xmpp.boundjid.user self.plugins_autoloaded = False self.plugin_manager = PluginManager(self) self.events = events.EventHandler() # global commands, available from all tabs # a command is tuple of the form: # (the function executing the command. Takes a string as argument, # a string representing the help message, # a completion function, taking a Input as argument. Can be None) # The completion function should return True if a completion was # made ; False otherwise self.commands = { 'help': (self.command_help, '\_o< KOIN KOIN KOIN', self.completion_help), 'join': (self.command_join, _("Usage: /join [room_name][@server][/nick] [password]\nJoin: Join the specified room. You can specify a nickname after a slash (/). If no nickname is specified, you will use the default_nick in the configuration file. You can omit the room name: you will then join the room you\'re looking at (useful if you were kicked). You can also provide a room_name without specifying a server, the server of the room you're currently in will be used. You can also provide a password to join the room.\nExamples:\n/join room@server.tld\n/join room@server.tld/John\n/join room2\n/join /me_again\n/join\n/join room@server.tld/my_nick password\n/join / password"), self.completion_join), 'exit': (self.command_quit, _("Usage: /exit\nExit: Just disconnect from the server and exit poezio."), None), 'quit': (self.command_quit, _("Usage: /quit\nQuit: Just disconnect from the server and exit poezio."), None), 'next': (self.rotate_rooms_right, _("Usage: /next\nNext: Go to the next room."), None), 'prev': (self.rotate_rooms_left, _("Usage: /prev\nPrev: Go to the previous room."), None), 'win': (self.command_win, _("Usage: /win \nWin: Go to the specified room."), self.completion_win), 'w': (self.command_win, _("Usage: /w \nW: Go to the specified room."), self.completion_win), 'move_tab': (self.command_move_tab, _("Usage: /move_tab \nMove Tab: Insert the tab at the position of . This will make the following tabs shift in some cases (refer to the documentation). A tab can be designated by its number or by the beginning of its address."), self.completion_move_tab), 'show': (self.command_status, _('Usage: /show [status message]\nShow: Sets your availability and (optionally) your status message. The argument is one of \"available, chat, away, afk, dnd, busy, xa\" and the optional [status message] argument will be your status message.'), self.completion_status), 'status': (self.command_status, _('Usage: /status [status message]\nStatus: Sets your availability and (optionally) your status message. The argument is one of \"available, chat, away, afk, dnd, busy, xa\" and the optional [status message] argument will be your status message.'), self.completion_status), 'bookmark_local': (self.command_bookmark_local, _("Usage: /bookmark_local [roomname][/nick]\nBookmark Local: Bookmark locally the specified room (you will then auto-join it on each poezio start). This commands uses almost the same syntaxe as /join. Type /help join for syntaxe examples. Note that when typing \"/bookmark\" on its own, the room will be bookmarked with the nickname you\'re currently using in this room (instead of default_nick)"), self.completion_bookmark_local), 'bookmark': (self.command_bookmark, _("Usage: /bookmark [roomname][/nick] [autojoin] [password]\nBookmark: Bookmark online the specified room (you will then auto-join it on each poezio start if autojoin is specified and is 'true'). This commands uses almost the same syntaxe as /join. Type /help join for syntaxe examples. Note that when typing \"/bookmark\" on its own, the room will be bookmarked with the nickname you\'re currently using in this room (instead of default_nick)"), self.completion_bookmark), 'set': (self.command_set, _("Usage: /set [plugin|][section]