#!/usr/bin/env python
# -*- coding: latin1 -*-
import sys
import time
import re
import getopt
import errno
from string import *
import curses.ascii
import curses.wrapper
import os
import signal
import socket
import shutil
import struct
import fcntl
import termios
import urllib
import commands
from __init__ import VERSION
import MSN
import ui
### Options #####
SEND_TYPING= 1
SHOW_INVITED= 1
AUTO_LIST= 1
AUTO_LIST_ON_0= 0
AUTO_LIST_ON_0_CLEAR= 0
AUTO_LIST_LAST_MOVE= 0
BEEP_ON_MSG= 0
BEEP_ON_NEW_CHAT= 0
MAX_NAME_SIZE= 0
TIMESTAMP= 1
TIMESTAMP_FORMAT= '[%H:%M]'
DELETE_KEY= -1 # keycode of the BACKSPACE key in your system
MONOCHROME= 0
CHAT_TITLE= 'user'
CHAT_TITLE_USE_ALIAS= 1
PING_TIME= 0
IDLE_TIME= 0
IDLE_STATE= 'IDL'
AUTO_UNIDLE= 0
AUTO_ADD_TO_ALLOWED= 1
EXEC_ON_MSG= ''
EXEC_ON_NEW_CHAT= ''
EXEC_ON_FILE_RECV_BEGIN= ''
EXEC_ON_FILE_RECV_END= ''
EXEC_ON_PAL_STATE_NLN= ''
EXEC_ON_PAL_STATE_CHANGE= ''
EXEC_ON_PAL_CONNECTED= ''
EXEC_ON_PAL_DISCONNECTED= ''
EXEC_ON_NEW_MAIL= ''
#################
PROG_NAME= 'Pebrot'
EXE_NAME= 'pebrot.py'
INIT_STATE= 'NLN'
CONFIG_DIR= os.getenv('HOME') + '/.pebrot/'
CONFIG_FILE= CONFIG_DIR + 'pebrotrc'
LOGO_FILE= sys.prefix + '/share/doc/pebrot/logos/pebrot.txt'
MAIN_LOG_DIR= CONFIG_DIR + 'logs/'
MSN.DEBUG= 0
MSN.VERBOSE= 1
LISTLINE= '----------%s----------'
IP_URL= 'http://simple.showmyip.com'
USER=''
PASSWD=''
HELPMSG= _(r'''Commands begin with '\' or '/', everything else are messages.
\number Create chat to user with this number.
\c Close active chat.
tab Change active chat.
\i number Invite user to active chat.
\l List connected users.
\l list Show requested list. list must be one of the following:
fl: Forward list, users on your contact list
rl: Reverse list, users who have you on their contact list
al: Allow list, users allowed to see your status
bl: Block list, users not allowed to see your status
\u List users on active chat.
\n Change nick.
\a user Add user to buddy list.
\b user Block user.
\r user Remove user from buddylist. import
\o user Open chat window with a user not on your buddy list.
\s state Change state. state must be one of the following:
nln: Online fln: Offline hdn: Appear Offline
idl: Idle awy: Away bsy: Busy
brb: Be Right Back phn: On the Phone lun: Out to Lunch
\f filePath Send file.
\fa Accept file for download.
\fr pos Reject file for download. pos specifies its position on chat
bar (1,2,3....). Can input several numbers at once, just
separate them with spaces.
If executed without any pos just rejects all file downloads
\fc pos Cancel file send. pos works like in '\fr'
\! Execute shell command.
\e Erase chat window contents.
\d file Dump chat text to file. If no file is supplied it will use a
temporal file name.
Ctrl-l Redraw screen.
\h \? This help.
\q Ctrl-d Quit.''')
USAGE= _(r'''%s - version %s
usage: %s [-d] [-m] [-u user] [-s state]
-d debug output
-u user log in with alternate user
-m monochrome. Don't use colors
-s state initial state. state must be one of the following:
NLN: Online
FLN: Offline
HDN: Appear Offline
IDL: Idle
AWY: Away
BSY: Busy
BRB: Be Right Back
PHN: On the Phone
LUN: Out to Lunch
''') % (PROG_NAME, VERSION, EXE_NAME)
VER_MSG= _('''Version - %s
Enter \h for help.\n\n''') % VERSION
IMG_COLORS= {
'R': 'RED',
'G': 'GREEN',
'Y': 'YELLOW',
'W': 'WHITE',
'B': 'BLUE',
'C': 'CYAN',
'M': 'MAGENTA',
}
COLORABLE= [
'DEFAULT',
'INFO',
'INFO_DELIM',
'ERROR',
'ERROR_DELIM',
'CHAT_BAR',
'CHAT_BAR_NAME',
'CHAT_BAR_NAME_TYPING',
'STATE_BAR',
'STATE_BAR_WRITTEN',
'STATE_BAR_NOT_WRITTEN',
'MY_NAME',
'OTHERS_NAME',
'LIST_DELIM',
'LIST_NUM',
'LIST_PASS',
'LIST_STATE',
'LIST_PARENS',
'LIST_NAME',
'TIMESTAMP'
]
def onlyCreated( x ):
return x.created
class TextMSN(MSN.Session):
def __init__( self, stdscr ):
MSN.Session.__init__( self )
self.stdscr= stdscr
self.usersList= {}
self.firstKeyPress= 1
self.altPressed= 0
self.history= []
self.historyIndex= 0
self.accounts= {}
self.COLORS= {}
self.alias= {}
self.lastPing= 0
self.lastStartedTyping= time.time()
self.typingCommand= 0
self.needToSendTypingNotif= 1
self.needToResetTypingNotif= 0
self.idle= 0
# To handle terminal resize
signal.signal(signal.SIGWINCH, self.handleResize)
# To handle defunct childs
signal.signal(signal.SIGCHLD, self.handleDefunct)
curses.use_env( 1 )
# Lets add chat 0 (the one in window 0 )
chat= MSN.Chat( self )
chat.ready= 0
self.chats['']= chat
self.sortedChats= [chat]
self.activeChat= chat
# set alarm handler for typing notifications
signal.signal( signal.SIGALRM, self.alarmHandler )
self.lastPing= time.time()
self.defineColors()
if curses.has_colors() and not MONOCHROME:
self.setColors( curses.COLOR_BLACK )
self.defaultColors()
(self.maxY, self.maxX)= self.stdscr.getmaxyx()
#self.StateBar= curses.newwin( 1, self.maxX, 0, 0 )
self.StateBar= ui.MyScrollWin( 1, self.maxX, 0, 0 )
self.Main= ui.MyWinStack( self.maxY-4, self.maxX, 1, 0 )
self.ChatBar= ui.MyScrollWin( 1, self.maxX, self.maxY-3, 0 )
self.Text= ui.MyInputWin( 2, self.maxX, self.maxY-2, 0 )
#print >>sys.stderr, 'COLORS:', str(self.COLORS)
#print >>sys.stderr, 'DEFAULT:', self.COLORS['DEFAULT']
#Add initial chat
self.Main.newWin( chat )
def defineColors( self ):
colors= ['WHITE', 'BLUE', 'RED', 'CYAN', 'YELLOW', 'GREEN', 'MAGENTA' ]
for f in (COLORABLE + colors):
self.COLORS[f]= ''
def defaultColors( self ):
self.COLORS['DEFAULT']= self.COLORS['WHITE']
self.COLORS['INFO']= self.COLORS['CYAN']
self.COLORS['INFO_DELIM']= self.COLORS['RED']
self.COLORS['ERROR']= self.COLORS['YELLOW']
self.COLORS['ERROR_DELIM']= self.COLORS['RED']
self.COLORS['CHAT_BAR']= self.COLORS['BLUE']
self.COLORS['CHAT_BAR_NAME']= self.COLORS['BLUE']
self.COLORS['CHAT_BAR_NAME_TYPING']= self.COLORS['GREEN']
self.COLORS['STATE_BAR']= self.COLORS['BLUE']
self.COLORS['STATE_BAR_WRITTEN']= self.COLORS['YELLOW']
self.COLORS['STATE_BAR_NOT_WRITTEN']= self.COLORS['BLUE']
self.COLORS['MY_NAME']= self.COLORS['BLUE']
self.COLORS['OTHERS_NAME']= self.COLORS['RED']
self.COLORS['LIST_DELIM']= self.COLORS['WHITE']
self.COLORS['LIST_NUM']= self.COLORS['RED']
self.COLORS['LIST_PASS']= self.COLORS['BLUE']
self.COLORS['LIST_STATE']= self.COLORS['GREEN']
self.COLORS['LIST_PARENS']= self.COLORS['WHITE']
self.COLORS['LIST_NAME']= self.COLORS['WHITE']
self.COLORS['TIMESTAMP']= self.COLORS['WHITE']
def initBarColors( self ):
if curses.has_colors() and not MONOCHROME:
self.ChatBar.attrset( self.COLORS['CHAT_BAR'] )
self.StateBar.attrset( self.COLORS['STATE_BAR'] )
self.Text.setAttr( self.COLORS['DEFAULT'] )
#self.showChatBar()
#self.showStateBar()
def termSize( self, ):
try:
return int(os.environ["LINES"]), int(os.environ["COLUMNS"])
except KeyError:
height, width = struct.unpack(
"hhhh", fcntl.ioctl(0, termios.TIOCGWINSZ ,"\000"*8))[0:2]
if not height:
return 25, 80
return height, width
def reinitCurses( self ):
while 1:
try:
curses.endwin();
self.stdscr= curses.initscr()
break
except curses.error, e:
time.sleep(1)
def handleDefunct( self, a, b ):
# Let's clean those zombie sons >:-]
try:
os.wait()
except OSError:
pass
def handleResize( self, a, b ):
#stdscr= curses.initscr()
#self.stdscr= stdscr
#size= self.termSize()
#(self.maxY, self.maxX)= size[0], size[1]
self.reinitCurses()
try:
self.maxY, self.maxX= self.stdscr.getmaxyx()
#print >>sys.stderr, 'maxX= %d, maxY= %d' % (self.maxX, self.maxY)
if self.maxY-3 >= 6:
self.StateBar.resize( 1, self.maxX, 0, 0 )
self.Main.resize( self.maxY-4, self.maxX, 1, 0 )
self.ChatBar.resize( 1, self.maxX, self.maxY-3, 0 )
self.Text.resize( 2, self.maxX, self.maxY-2, 0 )
self.refreshAll()
except curses.error, e:
pass
def setColors( self, background ):
try:
import usedefault
usedefault.use_default_colors()
back= -1
except ImportError:
back= background
curses.init_pair( 1, curses.COLOR_WHITE, back )
curses.init_pair( 2, curses.COLOR_BLUE, back )
curses.init_pair( 3, curses.COLOR_RED, back )
curses.init_pair( 4, curses.COLOR_CYAN, back )
curses.init_pair( 5, curses.COLOR_YELLOW, back )
curses.init_pair( 6, curses.COLOR_GREEN, back )
curses.init_pair( 7, curses.COLOR_MAGENTA, back )
curses.init_pair( 8, curses.COLOR_MAGENTA, back )
self.COLORS['WHITE']= curses.color_pair( 1 )
self.COLORS['BLUE']= curses.color_pair( 2 )
self.COLORS['RED']= curses.color_pair( 3 )
self.COLORS['CYAN']= curses.color_pair( 4 )
self.COLORS['YELLOW']= curses.color_pair( 5 )
self.COLORS['GREEN']= curses.color_pair( 6 )
self.COLORS['MAGENTA']= curses.color_pair( 7 )
#self.stdscr.touchwin()
#self.stdscr.refresh()
#self.stdscr.bkgdset( curses.color_pair(8) )
def pActive( self, text, color= None, refresh= 1 ):
#(y,x)= curses.getsyx()
if color == None:
color= 'DEFAULT'
if curses.has_colors() and not MONOCHROME:
self.Main.addstr( self.activeChat, '%s' % (text)
, self.COLORS[color] )
else:
self.Main.addstr( self.activeChat, '%s' % (text) )
#curses.setsyx( y, x )
if refresh:
self.refreshWin()
self.Text.refresh()
def pWin( self, chat, text, color= None, refresh= 1 ):
if color == None:
color= 'DEFAULT'
try:
if curses.has_colors() and not MONOCHROME:
self.Main.addstr( chat, text, self.COLORS[color] )
else:
self.Main.addstr( chat, text )
except TypeError, e:
self.pError( _('Type error when displaying text: %s') % str(e) )
#curses.setsyx( y, x )
if refresh and self.activeChat == chat:
#self.pDebug( 'REFRESH' )
self.refreshWin( chat )
self.Text.refresh()
def pVerbose( self, level, st ):
if level >= MSN.VERBOSE:
self.pWin( self.activeChat, st )
def refreshWin( self, chat= None ):
if not chat:
chat= self.activeChat
self.Main.refresh( chat )
def refreshAll( self ):
#self.stdscr.refresh()
#print >>sys.stderr, '-- STATE BAR --'
#self.initBarColors()
self.showStateBar()
#print >>sys.stderr, '-- MAIN --'
self.refreshWin()
#print >>sys.stderr, '-- CHAT BAR --'
self.showChatBar()
#print >>sys.stderr, '-- TEXT --'
self.Text.refresh()
def addHistory( self, line ):
self.history.append( line )
self.historyIndex= len( self.history )
def showPrevHistory( self ):
if self.historyIndex > 0:
self.historyIndex= self.historyIndex - 1
self.Text.erase()
self.Text.addstr( self.history[self.historyIndex] )
self.Text.refresh()
def showNextHistory( self ):
if self.historyIndex < len( self.history ) - 1:
self.historyIndex= self.historyIndex + 1
self.Text.erase()
self.Text.addstr( self.history[self.historyIndex] )
self.Text.refresh()
def pInfo( self, text, chat= None ):
if not chat:
chat= self.activeChat
self.pWin( chat, '>> ', 'INFO_DELIM' )
self.pWin( chat, text, 'INFO' )
self.pWin( chat, ' <<\n', 'INFO_DELIM' )
def aliasOrName( self, passport ):
if self.alias.has_key( passport ):
name= self.alias[passport]
else:
try:
name= self.usersList[passport]['name']
except KeyError:
name= passport
return name
def pChat( self, chat, passport, msg ):
if passport == self.user:
name= self.name
color= 'MY_NAME'
chat.written= 0
else:
name= self.aliasOrName( passport )
color= 'OTHERS_NAME'
if BEEP_ON_MSG:
curses.beep()
if EXEC_ON_MSG:
escMsg= re.escape( msg )
escName= re.escape( name )
self.execAction( EXEC_ON_MSG, {'$passport':passport
, '$user':escName, '$msg':escMsg} )
chat.written= 1
chat.activateUser( passport )
if MAX_NAME_SIZE > 0:
name= name[:MAX_NAME_SIZE]
if TIMESTAMP:
self.pWin( chat, '%s ' % time.strftime(TIMESTAMP_FORMAT
, time.localtime()), 'TIMESTAMP' )
self.pWin( chat, '%s: ' % name, color )
self.pWin( chat, '%s\n' % msg )
chat.logText( '%s %s: %s' % (time.strftime('[%H:%M:%S]'
, time.localtime()) , passport, msg) )
def pError( self, text, chat= None ):
if not chat:
chat= self.activeChat
self.pWin( chat, '>> ', 'ERROR_DELIM' )
self.pWin( chat, text, 'ERROR' )
self.pWin( chat, ' <<\n', 'ERROR_DELIM' )
def fatalError( self, msg ):
#curses.endwin()
#print >>sys.stderr, 'Error:', msg
#self.refreshWin()
#sys.exit()
raise _('Error: ') + msg
def usage( self ):
print sys.stderr.write( USAGE + '\n' )
def parseArgs( self ):
global USER, INIT_STATE, MONOCHROME
args= split( '-m -d -u -s' )
try:
opts, args= getopt.getopt( sys.argv[1:], 'dmu:s:', args )
except getopt.GetoptError:
curses.endwin()
self.usage()
#self.refreshWin()
sys.exit( 1 )
for o, a in opts:
if o == '-d':
MSN.DEBUG= 1
if o == '-m':
MONOCHROME= 1
if o == '-s':
a= upper( a )
if not MSN.STATES.has_key( a ):
curses.endwin()
self.usage()
#self.refreshWin()
sys.exit( 1 )
INIT_STATE= a
if o == '-u':
USER= a
def readConfig( self, file ):
global USER, PASSWD, INIT_STATE, SHOW_INVITED, AUTO_LIST, BEEP_ON_MSG \
, BEEP_ON_NEW_CHAT, SEND_TYPING, MAX_NAME_SIZE \
, AUTO_LIST_ON_0, AUTO_LIST_ON_0_CLEAR, AUTO_LIST_LAST_MOVE \
, TIMESTAMP, TIMESTAMP_FORMAT, DELETE_KEY, CHAT_TITLE \
, CHAT_TITLE_USE_ALIAS, PING_TIME, IDLE_TIME, IDLE_STATE \
, AUTO_UNIDLE, LOGO_FILE, EXEC_ON_MSG, EXEC_ON_NEW_CHAT \
, EXEC_ON_FILE_RECV_BEGIN, EXEC_ON_FILE_RECV_END \
, EXEC_ON_PAL_STATE_NLN, EXEC_ON_PAL_STATE_CHANGE \
, EXEC_ON_PAL_CONNECTED, EXEC_ON_PAL_DISCONNECTED \
, AUTO_ADD_TO_ALLOWED
try:
f= open( file )
except IOError:
self.fatalError( _('Opening config file \'%s\'') % file )
l= f.readline()
lastUser=''
while l:
l= strip(l)
if len(l) > 0:
if l[0] == '#':
self.pDebug( 'comment' )
else:
(opt, value)= split(l, '=', 1)
opt= strip( opt )
value= strip( value )
if opt == 'user':
if USER == '':
USER= value
lastUser= value
self.accounts[value]= ''
elif opt == 'password':
if PASSWD == '':
PASSWD= value
if lastUser == '':
if USER: # To catch error later (no user defined)
self.fatalError( _('Reading config file \'%s\', password \'%s\' must have a preceding \'user\' option') % (file, value) )
else:
self.accounts[lastUser]= value
lastUser= ''
elif opt == 'state':
INIT_STATE= upper( value )
elif opt == 'encoding':
MSN.ENCODING= value
elif opt == 'show_invited':
if value == '1':
SHOW_INVITED= 1
elif value == '0':
SHOW_INVITED= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'auto_list':
if value == '1':
AUTO_LIST= 1
elif value == '0':
AUTO_LIST= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'beep_on_msg':
if value == '1':
BEEP_ON_MSG= 1
elif value == '0':
BEEP_ON_MSG= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'beep_on_new_chat':
if value == '1':
BEEP_ON_NEW_CHAT= 1
elif value == '0':
BEEP_ON_NEW_CHAT= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'send_typing':
if value == '1':
SEND_TYPING= 1
elif value == '0':
SEND_TYPING= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'download_dir':
MSN.DOWNLOAD_DIR= value
if MSN.DOWNLOAD_DIR[-1] != '/':
MSN.DOWNLOAD_DIR= MSN.DOWNLOAD_DIR + '/'
elif opt == 'max_name_size':
try:
MAX_NAME_SIZE= int(value)
except ValueError:
self.fatalError( _('Reading config file \'%s\', \'%s\' must be an integer number') % (file, opt) )
elif opt == 'auto_list_on_0':
if value == '1':
AUTO_LIST_ON_0= 1
elif value == '0':
AUTO_LIST_ON_0= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'auto_list_on_0_clear':
if value == '1':
AUTO_LIST_ON_0_CLEAR= 1
elif value == '0':
AUTO_LIST_ON_0_CLEAR= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'auto_list_last_move':
if value == '1':
AUTO_LIST_LAST_MOVE= 1
elif value == '0':
AUTO_LIST_LAST_MOVE= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'pal_connect_timeout':
try:
MSN.PAL_CONNECT_TIMEOUT= int(value)
except ValueError:
self.fatalError( _('Reading config file \'%s\', \'%s\' must be an integer number') % (file, opt) )
elif opt == 'timestamp':
if value == '1':
TIMESTAMP= 1
elif value == '0':
TIMESTAMP= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'log_chats':
if value == '1':
MSN.LOG_CHATS= 1
elif value == '0':
MSN.LOG_CHATS= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'delete_key':
try:
if value[:2] == '0x':
DELETE_KEY= int(value[2:], 16)
else:
DELETE_KEY= int(value)
except ValueError:
self.fatalError( _('Reading config file \'%s\', \'%s\' must be an integer number') % (file, opt) )
elif opt == 'timestamp_format':
TIMESTAMP_FORMAT= value
elif opt == 'chat_title':
if value in ['number', 'user', 'both']:
CHAT_TITLE= value
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values number, user or both') % (file, opt) )
elif opt == 'alias':
l= split( value, ' ', 1 )
if len(l) == 2:
self.alias[l[0]]= l[1]
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\': malformed alias') % (file, opt) )
elif opt == 'chat_title_use_alias':
if value == '1':
CHAT_TITLE_USE_ALIAS= 1
elif value == '0':
CHAT_TITLE_USE_ALIAS= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'ping_time':
try:
PING_TIME= int(value)
except ValueError:
self.fatalError( _('Reading config file \'%s\', \'%s\' must be an integer number') % (file, opt) )
elif opt == 'idle_time':
try:
IDLE_TIME= int(value)
except ValueError:
self.fatalError( _('Reading config file \'%s\', \'%s\' must be an integer number') % (file, opt) )
elif opt == 'idle_state':
IDLE_STATE= upper(value)
if not MSN.STATES.has_key( IDLE_STATE ):
self.fatalError( _('Reading config file \'%s\', \'%s\' must be a valid state') % (file, opt) )
elif opt == 'auto_add_to_allowed':
if value == '1':
AUTO_ADD_TO_ALLOWED= 1
elif value == '0':
AUTO_ADD_TO_ALLOWED= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'auto_unidle':
if value == '1':
AUTO_UNIDLE= 1
elif value == '0':
AUTO_UNIDLE= 0
else:
self.fatalError( _('Reading config file \'%s\', option \'%s\' only can get values 1 or 0') % (file, opt) )
elif opt == 'logo_file':
if value != '' and value[0] == '/':
LOGO_FILE= value
else:
LOGO_FILE= sys.prefix + '/share/doc/pebrot/' + value
elif opt == 'my_ip':
MSN.MY_IP= value
elif opt[:4] == 'col_':
if not curses.has_colors():
l= f.readline()
continue
if self.COLORS.has_key( opt[4:].upper() ):
color= value.upper()
#print >>sys.stderr, 'color=', color
if not self.COLORS.has_key( color ):
self.fatalError( _('Reading config file \'%s\', \'%s\' has a non valid color value (%s)') % (file, opt, value) )
self.COLORS[opt[4:].upper()]= self.COLORS[color]
else:
self.fatalError( _('Reading config file \'%s\', \'%s\' is not a valid color option') % (file, opt) )
elif opt[:8] == 'exec_on_':
opt= opt.upper()
try:
exec(opt)
except NameError:
self.fatalError( _('Reading config file \'%s\', \'%s\' is not a valid option') % (file, opt) )
exec( '%s= \'%s\'' % (opt, value), globals() )
else:
self.fatalError( _('Reading config file \'%s\', unknown option \'%s\' ')
% (file, opt) )
l= f.readline()
#MSN.Session.__init__( self )
#print >>sys.stderr, 'COLORS=', self.COLORS
#self.showChatBar()
#self.showStateBar()
def connect( self, user, passwd, state ):
self.pVerbose( 1, _('User: %s\n') % user )
MSN.Session.connect( self, user, passwd, state )
def getPassword( self ):
if USER == '':
self.fatalError( _('No user or password, you should take a look at README ;)') )
if self.accounts.has_key( USER ) and self.accounts[USER]:
passwd= self.accounts[USER]
else:
self.pActive( _('Enter password for %s: ') % USER )
passwd= strip( self.Text.getLine( self.handleInput, hidden= 1 ) )
self.pActive('\n')
return passwd
def printUsers( self, chat= None, hash=None, title= _('=| CONNECTED |=')
, numbers=1, state=1, name=1 ):
if not chat:
chat= self.activeChat
if hash:
users= hash.keys()
else:
users= self.usersList.keys()
i= 0
users.sort()
self.pWin( chat, '\n', refresh= 0 )
self.pWin( chat, (LISTLINE % title) + '\n', color= 'LIST_DELIM' )
for pal in users:
if numbers:
self.pWin( chat, str(i), 'LIST_NUM', 0 )
self.pWin( chat, '- ', 'DEFAULT', 0 )
self.pWin( chat, '%s ' % pal, 'LIST_PASS', 0 )
if state:
self.pWin( chat, '(', 'LIST_PARENS', 0 )
self.pWin( chat, MSN.STATES[self.usersList[pal]['state']]
, 'LIST_STATE', 0 )
self.pWin( chat, ')', 'LIST_PARENS', 0 )
if name:
self.pWin( chat, ': ', 'LIST_PARENS', 0 )
if self.alias.has_key( pal ):
name= self.alias[pal]
else:
name= replace(self.usersList[pal]['name'], '\r', '')
self.pWin( chat, '%s' % name, 'LIST_NAME', 0 )
self.pWin( chat, '\n' )
#content= content + '%d- %s (%s): %s\n' % ( i
#, pal
#, MSN.STATES[self.usersList[pal]['state']]
#, self.usersList[pal]['name'] )
i= i + 1
#self.pMain( (LISTLINE % ('-' * len(title))) + '\n' )
if TIMESTAMP:
self.pWin( chat, '------------= %s =------------\n' % time.strftime(TIMESTAMP_FORMAT
, time.localtime()), 'TIMESTAMP' )
else:
self.pWin( chat, (LISTLINE % ('-' * len(title))) + '\n', refresh= 0
, color= 'LIST_DELIM' )
self.refreshWin()
self.Text.refresh()
def printList( self, chat, title, content ):
self.pWin( chat, '\n' )
self.pWin( chat, (LISTLINE % title) + '\n' )
self.pWin( chat, content + '\n' )
self.pWin( chat, (LISTLINE % ('-' * len(title))) + '\n' )
def updateUsersList( self ):
self.usersList= {}
for user in self.usersOnline.keys():
self.usersList[user]= self.usersOnline[user]
def nextChat( self ):
if SHOW_INVITED:
list= self.sortedChats
else:
list= filter( onlyCreated, self.sortedChats )
elems= len(list)
if elems == 0:
return None
else:
if self.activeChat in list:
i= list.index( self.activeChat )
return list[(i+1)%elems]
else:
return list[-1]
def dumpFileName( self ):
pref= 'pebrot-dump'
name= pref
i= 0
while( 1 ):
if not os.access( name, os.F_OK ):
return name
else:
name= pref + '-' + str(i)
i+= 1
def helpInfo( self ):
self.printList( self.activeChat, _('=| HELP |='), HELPMSG )
def processInput( self, st ):
st= strip( st )
parts= split( st )
if len(parts) == 0:
return
# Added to allow Pebrot to remain offline
if self.state == 'FLN':
if parts[0][1:] == 'q':
sys.exit()
elif parts[0][1:] == 's':
if len(parts)<2:
self.pInfo( _('state: %s') % MSN.STATES[self.state] )
else:
state= upper( parts[1] )
if state != 'FLN' and MSN.STATES.has_key( state ):
self.state = state
self.reconnect()
self.idle= 0
#self.lastStartedTyping= time.time()
#self.alarmExecAndProgramNext()
else:
self.helpInfo()
return
else:
self.pError( _('Error: Must be online to send commands or messages.') )
return
# End Edit
if parts[0][0] in ['\\', '/']:
command= parts[0][1:]
self.pDebug( 'com=' + command )
if command.isdigit():
if ( int(command) >= len(self.usersList) ):
self.pError( _('Error: Select an existing user number') )
return
if self.state in ['HDN', 'FLN']:
self.pError( _('Error: Must be online for talking') )
return
allUsers= self.usersList.keys()
allUsers.sort()
user= allUsers[int(command)]
if user == self.user:
self.pInfo( _('You can\'t talk to yourself') )
return
chat= self.newChat( user )
self.sortedChats.append( chat )
self.activeChat= chat
self.Main.newWin( chat )
self.refreshWin()
self.showChatBar()
self.showStateBar()
elif command == 'h' or command == '?':
self.helpInfo()
elif command == 'l':
if len(parts) == 1:
self.printUsers()
elif len(parts) == 2:
list= upper( parts[1] )
if list in ['FL', 'RL', 'AL', 'BL']:
self.printUsers( hash= self.lists[list]
, title= (_('=| USERS ON %s |=') % MSN.LISTS[list])
, numbers=0, state=0, name=0 )
else:
self.helpInfo()
else:
self.helpInfo()
elif command == 'i':
if len(parts)<2:
self.helpInfo()
return
if self.activeChat == self.sortedChats[0]:
self.pInfo( _('Must be on active chat to invite') )
return
allUsers= self.usersList.keys()
allUsers.sort()
nUser = int(parts[1])
if (nUser<0 or nUser>=len(allUsers)):
self.pError( _('User with this number does not exist') )
return
user= allUsers[nUser]
self.activeChat.invite( user )
elif command == 'c':
if self.activeChat != self.sortedChats[0]:
self.pDebug( _('closing chat %s') % str(self.activeChat) )
try:
self.closeChat( self.activeChat )
except MSN.SocketError, e:
pass
self.sortedChats.remove( self.activeChat )
self.Main.delWin( self.activeChat )
self.activeChat= self.nextChat()
#if len(self.chats.keys()) == 0:
#self.activeChat= None
self.refreshWin()
self.showChatBar()
self.showStateBar()
elif command == 'a':
if len(parts)<2:
self.helpInfo()
else:
self.delUser( parts[1], 'BL' )
self.addUser( parts[1], 'AL' )
self.addUser( parts[1], 'FL' )
elif command == 'b':
if len(parts)<2:
self.helpInfo()
else:
self.delUser( parts[1], 'AL' )
self.addUser( parts[1], 'BL' )
elif command == 'r':
if len(parts)<2:
self.helpInfo()
else:
self.delUser( parts[1], 'AL' )
self.delUser( parts[1], 'FL' )
elif command == 'u':
if self.activeChat != self.sortedChats[0]:
self.showChatUsers( self.activeChat )
elif command == 'o':
if len(parts)<2:
self.helpInfo()
else:
if self.state in ['HDN', 'FLN']:
self.pError( _('Error: Must be online for talking') )
return
user= parts[1]
if user == self.user:
self.pInfo( _('You can\'t talk to yourself') )
return
if not "@" in user:
self.pError( _('You must use give the full passport address. Ex.: somebody@example.com') )
return
chat= self.newChat( user )
self.sortedChats.append( chat )
self.activeChat= chat
self.Main.newWin( chat )
self.refreshWin()
self.showChatBar()
self.showStateBar()
elif command == 'n':
if len(parts) == 1:
self.pInfo( _('Name: %s') % self.name )
else:
self.changeName( join(parts[1:], ' ') )
elif command == 's':
if len(parts)<2:
self.pInfo( _('state: %s') % MSN.STATES[self.state] )
else:
state= upper( parts[1] )
if MSN.STATES.has_key( state ):
self.changeState( state )
self.idle= 0
self.lastStartedTyping= time.time()
self.alarmExecAndProgramNext()
else:
self.helpInfo()
elif command == 'p':
self.ping()
elif command == 'f':
if self.activeChat == self.sortedChats[0]:
self.pError( _('Must be connected to a chat for file sending') )
return
if len(parts)<2:
self.helpInfo()
return
file= join( parts[1:] )
if not os.access( file, os.R_OK ):
self.pError( _('Can\'t open \'%s\'') % file )
return
self.sendChatFile( self.activeChat, file )
elif command == 'fa':
for fRecv in self.activeChat.recvFile.values():
if fRecv.state != MSN.RECV_ACCEPTED:
fRecv.accept()
self.pInfo( _('Receiving \'%s\' accepted')
% (fRecv.fileName) )
elif command == 'fr':
if len(parts) == 1:
for fRecv in self.activeChat.recvFile.values():
fRecv.reject()
self.pInfo( _('Receiving \'%s\' rejected')
% (fRecv.fileName) )
self.showChatBar()
else:
recvs= self.activeChat.recvFile.values()
for num in parts[1:]:
num= int(num)
if num >= 1 and num <= len(recvs):
self.activeChat.closeFileRecv( recvs[num-1] )
self.pInfo( _('Aborting downloading number %d')
% num )
self.showChatBar()
else:
if len(recvs) == 0:
self.pError( _('There are no downloads to cancel') )
else:
self.pError( _('Number must be between 1 and %d')
% (len(recvs)) )
self.showChatBar()
elif command == 'fc':
if len(parts) == 1:
for fSend in self.activeChat.sendFile.values():
fSend.cancel()
self.removeFileSend( fSend )
self.pInfo( _('Sending \'%s\' rejected')
% (fSend.fileName) )
self.showChatBar()
else:
sends= self.activeChat.sendFile.values()
for num in parts[1:]:
num= int(num)
if num >= 1 and num <= len(sends):
self.activeChat.cancelFileSend( sends[num-1] )
self.pInfo( _('Cancelling sending number %d')
% num )
self.showChatBar()
else:
if len(sends) == 0:
self.pError( _('There are no downloads to cancel') )
else:
self.pError( _('Number must be between 1 and %d')
% (len(sends)) )
self.showChatBar()
elif command == '!':
com= join( parts[1:] )
(stdin, out)= os.popen4(com, 'r')
self.pActive( out.read() + '\n' )
elif command == 'e':
self.Main.erase( self.activeChat )
self.Main.toBottom( self.activeChat )
self.refreshWin()
self.Text.refresh()
elif command == 't':
self.pActive( str(self.termSize()) )
elif command == 'crash':
self.crash()
elif command == 'ex':
self.subExec( self.replaceVars(
'echo $user es una $prueba'
, {'$user':'de aqui', '$prueba':'kk' } ) )
## added for pebrot no error message shutdown
elif command == 'rec':
if self.offline == 1:
self.crash()
self.offline = 0
elif command == 'd':
if len( parts ) == 1:
name= self.dumpFileName()
else:
name= parts[1]
try:
f= open( name, 'w' )
except IOError:
self.pError( _('Can\'t open file \'%s\'') % name )
return
self.Main.dump( self.activeChat, f )
self.pInfo( _('Chat dumped to file %s') % name )
elif command == 'color':
if len( parts ) == 1:
self.pInfo( _('The colors are: %s') % self.COLORS )
elif len ( parts ) == 3:
#self.pInfo( _('%s') % parts[1] + ' and ' + parts[2] )
self.COLORS[ parts[1] ] = self.COLORS[ parts[2] ]
else:
self.pInfo( _('You messed up somehow and i can\'t fix it. :-P') )
elif command == 'q':
sys.exit()
else:
self.pError( _(r'Error: Unknown command: %s') % parts[0] )
else: # It's a message, lets send it
if AUTO_UNIDLE and self.idle:
self.changeState( 'NLN' );
self.idle= 0
self.lastStartedTyping= time.time()
self.alarmExecAndProgramNext()
if self.activeChat == self.sortedChats[0]:
self.pError( _('Error: You are not connected to any chat.') )
else:
self.sendChatMsg( self.activeChat, st )
# Invite pals who are out from chat (e.g. timeout kicked)
def inviteInactive( self ):
list= self.listInactiveUsers( self.activeChat )
if list:
t0= time.time()
for user in list:
self.activeChat.invite( user )
t1= time.time()
while self.listInactiveUsers( self.activeChat ) and \
(t1-t0) < MSN.PAL_CONNECT_TIMEOUT:
self.step()
t1= time.time()
self.pDebug( 'Waiting for pals to connect...(t1-t0= %s)'
% (t1-t0) )
if (t1-t0) >= MSN.PAL_CONNECT_TIMEOUT:
self.pError( _('Timeout while waiting for pals to connect') )
def showStateBar( self ):
self.StateBar.erase()
if curses.has_colors() and not MONOCHROME:
self.StateBar.attrset( self.COLORS['STATE_BAR'] )
if SHOW_INVITED:
list= self.sortedChats
else:
list= filter( onlyCreated, self.sortedChats )
#list= [None] + list
if curses.has_colors() and not MONOCHROME:
cBar= self.COLORS['STATE_BAR']
cWritten= self.COLORS['STATE_BAR_WRITTEN']
cNormal= self.COLORS['STATE_BAR_NOT_WRITTEN']
else:
cBar= cNormal= cWritten= 0
#self.pMain( str(list) )
i= 0
for chat in list:
if chat.written:
color= cWritten
if curses.has_colors() and not MONOCHROME:
plus= ''
else:
plus= '+'
else:
color= cNormal
plus= ''
if chat == self.activeChat:
self.StateBar.addstr( '[', cBar )
if CHAT_TITLE == 'number' or CHAT_TITLE == 'both':
self.StateBar.addstr( '%d' % i, color )
if CHAT_TITLE == 'both':
self.StateBar.addstr( '-', color )
if (CHAT_TITLE == 'user' or CHAT_TITLE == 'both'):
users= chat.listUsers()
if len( users ) == 0:
if chat == self.sortedChats[0]:
title= _('Main')
else:
title= _('Empty')
elif len( users ) == 1:
if CHAT_TITLE_USE_ALIAS and \
self.alias.has_key( users[0] ):
title= replace( self.alias[users[0]], ' ', '_' )
else:
title= users[0].split('@')[0]
else:
title= _('Multiple')
self.StateBar.addstr( '%s' % title, color )
self.StateBar.addstr( plus, color )
if chat == self.activeChat:
self.StateBar.addstr( ']', cBar )
i= i + 1
if list:
self.StateBar.addstr( ' ' )
self.StateBar.line()
self.StateBar.toTop()
self.StateBar.refresh()
self.Text.refresh()
# Find public ip using http://simple.showmyip.com
def getPublicIp( self ):
self.pActive( _('Querying public ip from simple.showmyip.com ') )
ip= ''
for i in range(10):
try:
st= urllib.urlopen( IP_URL ).read().strip()
ip= split( st )[0]
except IOError:
pass
self.pActive( '.' )
if ip != '':
self.pActive( ' %s\n' % ip )
return ip
self.pActive( _(' ERROR: can\'t read page\n') )
def showChatBar( self ):
self.ChatBar.erase()
if curses.has_colors() and not MONOCHROME:
self.ChatBar.attrset( self.COLORS['CHAT_BAR'] )
if self.activeChat != self.sortedChats[0]:
for fSend in self.activeChat.sendFile.values():
try:
percent= (float(fSend.sent)/fSend.size)*100
self.pDebug( '%s= (up: %d)' % ( str(self.sendFile)
, percent) )
self.ChatBar.addstr( _('(up: %d%%)') % percent )
except ZeroDivisionError:
pass
for fSend in self.activeChat.recvFile.values():
#asd
try:
percent= (float(fSend.received)/fSend.size)*100
self.pDebug( '%s= (dl: %d)' % ( str(self.recvFile)
, percent) )
self.ChatBar.addstr( _('(dl: %d%%)') % percent )
except ZeroDivisionError:
pass
users= self.activeChat.getUsers()
self.pDebug( 'USERS= ' + str(users) )
self.ChatBar.addstr( '>>' )
for u in users:
user= u[0].split('@')[0]
if curses.has_colors() and not MONOCHROME:
if u[1] == 'TYPING':
color= self.COLORS['CHAT_BAR_NAME_TYPING']
else:
color= self.COLORS['CHAT_BAR_NAME']
self.ChatBar.addstr( ' ' + user, color )
else:
if u[1] == 'TYPING':
self.ChatBar.addstr( ' *' + user )
else:
self.ChatBar.addstr( ' ' + user )
self.ChatBar.line()
self.ChatBar.toTop()
self.ChatBar.refresh()
self.Text.refresh()
def activateChat( self, num ):
if num < len(self.sortedChats):
self.activeChat= self.sortedChats[num]
self.refreshWin()
self.showChatBar()
self.showStateBar()
def handleInput( self, c ):
if c in [curses.ascii.BS, curses.ascii.DEL, curses.KEY_BACKSPACE
, DELETE_KEY]:
self.Text.delChar()
self.Text.refresh()
elif self.altPressed:
if c >= 0x30 and c <= 0x39:
self.activateChat( c - 0x30 )
elif c == 0x60: # Key left from number 1
self.activateChat( 0 )
elif c == 0x14a: # supr
self.Text.suprChar()
self.Text.refresh()
elif c == curses.KEY_LEFT:
self.Text.cursBack()
self.Text.refresh()
elif c == curses.KEY_RIGHT:
self.Text.cursForward()
self.Text.refresh()
elif c == curses.KEY_UP:
self.showPrevHistory()
elif c == curses.KEY_DOWN:
self.showNextHistory()
elif c == curses.KEY_PPAGE:
self.Main.scrollUp( self.activeChat, 5 )
self.Text.refresh()
elif c == curses.KEY_NPAGE:
self.Main.scrollDown( self.activeChat, 5 )
self.Text.refresh()
elif c == 0x9: # tab
self.activeChat= self.nextChat()
self.refreshWin()
self.showChatBar()
self.showStateBar()
elif c == curses.KEY_HOME: # Begin
self.Text.cursBegin()
self.Text.refresh()
elif c == curses.KEY_END: # End
self.Text.cursEnd()
self.Text.refresh()
elif c == 0x1b: # Alt pulsado
self.altPressed= 1
elif c == 0xc: # Ctrl-l (redraw window)
self.reinitCurses()
self.refreshAll()
elif c == 0x4: # Ctrl-d
sys.exit(0)
elif c > 255:
pass
else:
if c in [0x5c, 0x2f] and self.firstKeyPress:
# '\' for not sending typing notification with commands
self.typingCommand= 1
elif c != curses.ERR and SEND_TYPING and not self.typingCommand \
and self.needToSendTypingNotif and self.activeChat:
self.firstKeyPress= 0
self.needToSendTypingNotif= 0
self.lastStartedTyping= time.time()
# This alarm is for self.needToSendTypingNotif= 1 and sending
# a new typingNotification after 5 more seconds
signal.alarm( 5 )
self.needToResetTypingNotif= 1
try:
self.activeChat.typingNotification()
except MSN.SocketError, e:
pass
#self.pError( 'Socket Error 3: %s' % e[1] )
self.altPressed= 0
return 0
if c != 0x1b:
self.altPressed= 0
return 1
def alarmExecAndProgramNext( self ):
t= time.time()
self.pDebug( 'alarmExecAndProgramNext: lastPing= %s, t= %s' %
(str(self.lastPing), str(t)) )
# Setting to 600 as a failsafe, and because python appears not to have
# support for infinity
minTimeTillNext= 600
# Usage: a three element list per time-out action
# first element - should return true or false, according to whether
# the action should be considered.
# second element - should return the time the action is to be
# performed at. As with all deadlines, the action may be taken
# after it has passed, but never before.
# third element - the function to call to perform the action.
for [getcond, getdeadline, action] in [
[
lambda: PING_TIME,
lambda: self.lastPing + PING_TIME,
self.pingWrap
],
[
lambda: IDLE_TIME and self.state == 'NLN',
lambda: self.lastStartedTyping + IDLE_TIME,
self.idleTimeOut
],
[
lambda: self.needToResetTypingNotif,
lambda: self.lastStartedTyping + 5,
self.resetTypingNotif
]
]:
if getcond() and (t >= getdeadline()):
# action should change the deadline and/or cond,
# which is why we use lambdas
#self.pInfo( 'action %s called on %d' % (action, time.time()) )
action()
# Reset t in case action() takes a long time -
t = time.time()
delta= getdeadline() - t
#self.pInfo( ' %s - %s (%d)' % (delta, action, bool(getcond())) )
if getcond() and delta < minTimeTillNext:
minTimeTillNext= delta
#self.pInfo( 'minTimeTillNext= %s' % minTimeTillNext )
timeTillNext= int(minTimeTillNext) + 1
if timeTillNext <= 0:
timeTillNext= 1
#self.pInfo( 'alarm set to %d' % timeTillNext)
signal.alarm(timeTillNext)
def alarmHandler( self, signum, frame ):
self.alarmExecAndProgramNext()
def pingWrap( self ):
# It's time to ping server
self.ping()
#self.pInfo( 'PING - %s' % str(t) )
self.lastPing= time.time()
def resetTypingNotif( self ):
#self.pInfo( 'resetTypingNotif' )
self.needToResetTypingNotif= 0
self.needToSendTypingNotif= 1
for chat in self.chats.values():
for user in chat.listUsers():
if chat.isTyping( user ):
chat.activateUser( user )
self.showChatBar()
def idleTimeOut( self ):
# TODO - allow other actions (e.g. shell scripts)
self.idle= 1
self.pInfo( _('Automatically setting state to %s') %
MSN.STATES[IDLE_STATE] )
self.changeState( IDLE_STATE )
def printArt( self, chat, img, refresh= 0 ):
color= 'W'
i= 0
while i < len(img):
piece= ''
while i < len(img) and img[i] != '':
piece= piece + str(img[i])
i= i + 1
self.pWin( chat, piece, IMG_COLORS[upper(color)] )
if i < len(img):
color= img[i+1]
i= i + 2
self.pWin( chat, '\n', refresh= 0 )
if refresh:
self.refreshWin( chat )
self.Text.refresh()
def showChatUsers( self, chat ):
self.printUsers( chat, chat.users, _('=| USERS ON ACTIVE CHAT |='), 0 )
def oneStep( self ):
try:
st= self.Text.getLine( self.handleInput, self.step )
if st:
self.addHistory( st )
self.lastStartedTyping= time.time()
self.firstKeyPress= 1
self.typingCommand= 0
self.needToSendTypingNotif= 1
self.Text.erase()
self.refreshWin()
self.processInput( st )
except MSN.SocketError, e:
if e.errno() == errno.EINTR: # Avoid error 'Interrupted system call'
pass
else:
type= self.socketType( e.socket )
if type == MSN.SOCK_MAIN:
# Added to Fix offline status
if self.state != 'FLN':
self.pError( _('Socket error on main server connection (%s)') % e.errorMsg() )
self.pError( _('Trying to reconnect...') )
self.reconnect()
elif type == MSN.SOCK_RECV:
fRecv= self.recvFile[e.socket]
self.pError( _('Socket error receiving \'%s\' (%s)')
% (fRecv.fileName, e.errorMsg()), fRecv.chat )
self.removeFileRecv( fRecv )
self.showChatBar()
elif type == MSN.SOCK_SEND:
fSend= self.sendFile[e.socket]
self.pError( _('Socket error sending \'%s\' (%s)')
% (fSend.fileName, e.errorMsg()), fSend.chat )
self.removeFileSend( fSend )
self.showChatBar()
elif type == MSN.SOCK_CHAT:
# To hide errors when server closes idle chat
if not self.chats[e.socket].hideSocketError:
self.pError( _('Socket error (%s)') % e.errorMsg(),
self.chats[e.socket] )
else:
self.pError( _('Unhandled socket error (%s)')
% e.errorMsg() )
self.Text.refresh()
def replaceVars( self, action, params ):
#self.pInfo( str(params) )
#self.pInfo( action )
#return ''
try:
for var in re.findall( r'(?<=[^\\])\$\w+', action ):
var= lower( var )
self.pDebug( 'var=%s, params[var]=%s' % (var, str(params[var])) )
action= re.sub( '\\' + var, str(params[var]), action )
except KeyError, e:
self.pError( _('Variable \'%s\' not found in action \'%s\'')
% (e, action) )
return ''
return action
def subExec( self, command ):
if os.fork() == 0:
os.system( command )
os._exit( 0 )
def execAction( self, action, params ):
self.subExec( self.replaceVars( action, params ) )
def loopInput( self ):
while 1:
self.oneStep()
def getAutoListChat( self ):
if AUTO_LIST_ON_0:
chat= self.sortedChats[0]
if AUTO_LIST_ON_0_CLEAR:
self.Main.erase( chat )
else:
chat= self.activeChat
return chat
def drawLastMove( self, chat, msg ):
allUsers= self.usersList.keys()
allUsers.sort()
number= allUsers.index( msg.fields['passport'] )
self.pWin( chat, '%s' % number ,'LIST_NUM', 0 )
self.pWin( chat, '- ', 'DEFAULT', 0 )
self.pWin( chat, '%s ' % msg.fields['passport']
, 'LIST_PASS', 0 )
self.pWin( chat, _('changed state to '), 'DEFAULT', 0 )
self.pWin( chat
, '\'%s\'\n' % MSN.STATES[msg.fields['state']]
, 'LIST_STATE', 1 )
def userChangesState( self, msg ):
self.updateUsersList()
if AUTO_LIST:
chat = self.getAutoListChat()
self.printUsers( chat )
if AUTO_LIST_LAST_MOVE:
self.drawLastMove( chat, msg )
if msg.fields['state'] == 'NLN' and EXEC_ON_PAL_STATE_NLN:
passport= msg.fields['passport']
escName= re.escape( self.aliasOrName(passport) )
self.execAction( EXEC_ON_PAL_STATE_NLN, {'$passport':passport
, '$user':escName} )
elif EXEC_ON_PAL_STATE_CHANGE:
passport= msg.fields['passport']
escName= re.escape( self.aliasOrName(passport) )
state= msg.fields['state']
self.execAction( EXEC_ON_PAL_STATE_CHANGE, {'$passport':passport
, '$user':escName, '$state':state} )
def userConnected( self, msg ):
self.updateUsersList()
if AUTO_LIST:
chat = self.getAutoListChat()
self.printUsers( chat )
if AUTO_LIST_LAST_MOVE:
self.drawLastMove( chat, msg )
if EXEC_ON_PAL_CONNECTED:
passport= msg.fields['passport']
escName= re.escape( self.aliasOrName(passport) )
state= msg.fields['state']
self.execAction( EXEC_ON_PAL_CONNECTED, {'$passport':passport
, '$user':escName, '$state':state} )
def userOn( self, passport ):
self.updateUsersList()
# Lets reshow user list on init when an ILN arrives after it wasn't expected
if self.listShown:
chat = self.getAutoListChat()
self.printUsers( chat )
def userOff( self, passport ):
self.updateUsersList()
if AUTO_LIST:
chat = self.getAutoListChat()
self.printUsers( chat )
if AUTO_LIST_LAST_MOVE:
self.pWin( chat, '%s ' % passport, 'LIST_PASS', 0 )
self.pWin( chat, _('disconnected\n'), 'DEFAULT', 1 )
if EXEC_ON_PAL_DISCONNECTED:
escName= re.escape( self.aliasOrName(passport) )
self.execAction( EXEC_ON_PAL_DISCONNECTED, {'$passport':passport
, '$user':escName} )
def otherLogin( self ):
#self.fatalError( _('Detected other login to this account') )
self.pError( _('You have been signed in from another computer. Type \\q to exit or \\s nln to reconnect.') )
self.state = 'FLN'
self.pError( _('You are currently OFFLINE.') )
def userAdded( self, passport, list ):
list= upper( list )
self.pInfo( _('%s added to %s') % (passport, MSN.LISTS[list]) )
if AUTO_ADD_TO_ALLOWED and list == 'RL':
self.addUser( passport, 'FL' )
self.addUser( passport, 'AL' )
def userRemoved( self, passport, list ):
list= upper( list )
self.pInfo( _('%s removed from %s') % (passport, MSN.LISTS[list]) )
def selfStateChanged( self, state ):
self.pInfo( _('state: %s') % MSN.STATES[state] )
# This is for firing alarms after login
self.alarmExecAndProgramNext()
def invitedBy( self, msg ):
self.acceptChat( msg )
def msgFrom( self, chat, passport, msg ):
# Make chat visible on first msg received
self.pDebug(passport)
if chat not in self.sortedChats:
self.pInfo( _('%s is talking to you') % passport )
if BEEP_ON_NEW_CHAT:
curses.beep()
if EXEC_ON_NEW_CHAT:
escName= re.escape( self.aliasOrName(passport) )
escMsg= re.escape( msg )
self.execAction( EXEC_ON_NEW_CHAT, {'$passport':passport
, '$user':escName, '$msg':escMsg} )
if SHOW_INVITED:
self.sortedChats.append( chat )
# Lets try to reuse a chat window
oldChat = self.Main.reuseWindow( chat )
if oldChat:
self.delChat( oldChat )
self.sortedChats.remove( oldChat )
if self.activeChat == oldChat:
self.activeChat = chat
self.refreshWin()
else:
self.Main.newWin( chat )
# Avoid problems displaying \r
msg= replace( msg, '\r', '' )
self.pDebug( 'MSG===' + msg )
if SHOW_INVITED:
self.pChat( chat, passport, msg )
else:
self.pChat( self.activeChat, passport, msg )
self.showChatBar()
self.showStateBar()
def gotMail( self, numUnread ):
self.pInfo( _('You\'ve got mail: %s unread.') % numUnread )
def incomingMail( self, mailFrom, nameFrom ):
if EXEC_ON_NEW_MAIL:
escMail= re.escape( mailFrom )
escName= re.escape( nameFrom )
self.execAction( EXEC_ON_NEW_MAIL, {'$mailfrom':escMail, '$namefrom':escName} )
self.pInfo( _('Incoming mail from: %s <%s>') % (mailFrom, nameFrom) )
def userAcceptChat( self, chat, passport ):
if not self.Main.hasWin( chat ):
self.Main.newWin( chat )
self.pInfo( _('%s joined the chat') % passport, chat )
chat.logText( _('%s >> %s joined the chat <<') %
(time.strftime('[%H:%M:%S]'), passport) )
self.showStateBar()
self.showChatBar()
def nameChanged( self, name ):
self.name= name
self.pInfo( _('Name changed to: %s') % name )
def protoError( self, code ):
self.pError( _('Protocol error: %s') % MSN.ERRORS[code] )
def fatalProtoError( self, code ):
self.fatalError( _('Protocol error (%s)') % MSN.ERRORS[code] )
def addUserError( self, passport, list ):
self.pError( _('Failed to add \'%s\' to %s') %
(passport, MSN.LISTS[list]) )
def delUserError( self, passport, list ):
self.pError(
_('Failed to remove \'%s\' from %s (user wasn\'t on this list)') %
(passport, MSN.LISTS[list]) )
def userOnListError( self, passport, list ):
self.pError( _('User \'%s\' already on %s') %
(passport, MSN.LISTS[list]) )
def userLeavesChat( self, chat, user ):
self.pInfo( _('%s left the chat') % user, chat )
chat.logText( _('%s >> %s left the chat <<') %
(time.strftime('[%H:%M:%S]'), user) )
if len(chat.users) == 0:
if self.usersOnline.has_key(user):
chat.deactivateUser( user )
#chat.invite( user )
#else:
#self.sortedChats.remove( chat )
#if self.activeChat== chat:
#self.activeChat= self.nextChat()
self.showStateBar()
self.showChatBar()
def msgNotReceived( self, chat ):
self.pError( _('Message was not received'), chat )
def typing( self, chat, user ):
chat.typingUser( user )
self.showChatBar()
self.needToResetTypingNotif= 1
signal.alarm( 5 )
def chatConnectError( self, chat ):
self.pError( _('Can\'t connect to chat server'), chat )
def sendFileAccepted( self, fSend ):
self.pInfo( _('Request for sending \'%s\' accepted') % fSend.fileName
, fSend.chat )
def sendFileRejected( self, fSend ):
self.pInfo( _('Request for sending \'%s\' rejected') % fSend.fileName
, fSend.chat )
def sendFileCancelled( self, fSend ):
self.pInfo( _('Sending \'%s\' cancelled by peer') % fSend.fileName
, fSend.chat )
self.showChatBar()
def sendFileFinished( self, fSend ):
self.pInfo( _('\'%s\' successfully sent') % fSend.fileName, fSend.chat )
self.showChatBar()
def recvFileRequest( self, fRecv ):
passport= fRecv.user
name= self.aliasOrName( passport )
msg= _('Request for receiving file \'%s\' (%s bytes) from %s') % \
(fRecv.fileName, fRecv.size, fRecv.user)
# Make chat visible on first msg received
if fRecv.chat not in self.sortedChats:
self.pInfo( _('File send request received') )
if BEEP_ON_NEW_CHAT:
curses.beep()
if EXEC_ON_NEW_CHAT:
escName= re.escape( name )
escMsg= re.escape( msg )
self.execAction( EXEC_ON_NEW_CHAT, {'$passport':passport
, '$user':escName, '$msg':escMsg} )
if SHOW_INVITED:
self.sortedChats.append( fRecv.chat )
self.Main.newWin( fRecv.chat )
fRecv.chat.written= 1
self.pInfo( msg, fRecv.chat )
if EXEC_ON_FILE_RECV_BEGIN:
escName= re.escape( name )
escFile= re.escape( fRecv.fileName )
self.execAction( EXEC_ON_FILE_RECV_BEGIN, {'$passport':passport
, '$user':escName, '$file':escFile, '$size':fRecv.size } )
self.showChatBar()
self.showStateBar()
def chunkSent( self, fSend ):
if fSend.chat == self.activeChat:
self.showChatBar()
def chunkReceived( self, fRecv ):
if fRecv.chat == self.activeChat:
self.showChatBar()
def recvFileFinished( self, fRecv ):
self.pInfo( _('\'%s\' successfully received') % fRecv.fileName, fRecv.chat )
if EXEC_ON_FILE_RECV_END:
passport= fRecv.user
escName= re.escape( self.aliasOrName(passport) )
escFile= re.escape( fRecv.fileName )
self.execAction( EXEC_ON_FILE_RECV_END, {'$passport':passport
, '$user':escName, '$file':escFile, '$size':fRecv.size } )
self.showChatBar()
def recvFileCancelled( self, fRecv ):
self.pInfo( _('Receiving \'%s\' cancelled by peer') % fRecv.fileName
, fRecv.chat )
self.showChatBar()
def listUpdated( self, list, type ):
self.printUsers( self.activeChat
, list, '=| %s |=' % (upper(MSN.LISTS[type]))
, numbers=0, state=0, name=0 )
def palListComplete( self ):
self.printUsers()
#def qngReceived( self ):
#self.pInfo( 'QNG received' )
def userAddedYou( self, passport ):
self.pInfo( _('User %s added you to his/her list') % passport );
if AUTO_ADD_TO_ALLOWED:
self.addUser( passport, 'FL' )
self.addUser( passport, 'AL' )
def gogogo( stdscr ):
global PASSWD
curses.noecho()
stdscr.keypad(1)
#try:
con= TextMSN( stdscr )
con.readConfig( CONFIG_FILE )
con.parseArgs()
PASSWD= con.getPassword()
con.initBarColors()
con.refreshAll()
# Create dir for chat logs under MAIN_LOG_DIR
MSN.LOG_DIR= MAIN_LOG_DIR + USER + '/'
if MSN.LOG_CHATS and not os.access( MSN.LOG_DIR, os.F_OK ):
os.mkdir( MSN.LOG_DIR )
# Print logo
try:
f= open( LOGO_FILE )
LOGO= f.read()
con.printArt( con.activeChat, LOGO )
except IOError:
pass
con.pActive( VER_MSG )
if MSN.MY_IP == 'auto':
MSN.MY_IP= con.getPublicIp()
con.connect( USER, PASSWD, INIT_STATE )
# Just begin with the alarms
con.loopInput()
#except (KeyboardInterrupt):
#curses.endwin()
def replaceOldConfig( oldConfig ):
print
print _('Old config file found. I\'m going to move this config file to %s.') % CONFIG_FILE
raw_input( _('Press Enter to continue...') )
print
print _('Moving %s to %s ...') % (oldConfig, CONFIG_FILE)
os.rename( oldConfig, CONFIG_FILE )
print
raw_input( _('All done, press Enter to continue...') )
def main():
if not os.access( CONFIG_DIR, os.F_OK ):
os.mkdir( CONFIG_DIR )
if not os.access( MAIN_LOG_DIR, os.F_OK ):
os.mkdir( MAIN_LOG_DIR )
os.chmod( CONFIG_DIR, 0700 )
oldConfig= os.getenv('HOME') + '/.pebrotrc'
if os.access( oldConfig, os.F_OK ):
replaceOldConfig( oldConfig )
else:
if not os.access( CONFIG_FILE, os.R_OK ):
print _('I can\'t find %s, so I will copy the supplied pebrotrc there.') \
% CONFIG_FILE
raw_input( _('Press Enter to continue...') )
shutil.copyfile( sys.prefix + '/share/doc/pebrot/pebrotrc', CONFIG_FILE )
#os.chmod( CONFIG_FILE, 0600 )
print _('Please edit %s and specify your login and password.') \
% CONFIG_FILE
sys.exit()
curses.wrapper( gogogo )
if __name__ == '__main__':
sys.stderr.write( _('You should execute pebrot, not pebrot.py :)\n') )
|