summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormathieui <mathieui@mathieui.net>2013-04-05 23:57:53 +0200
committermathieui <mathieui@mathieui.net>2013-04-05 23:57:53 +0200
commit91b960b797bbf17f6c4b33279f2d406c5a2c93b2 (patch)
tree91cbb61f2618d448416f4a41043ef2327793a53b
parent16268ba96460c0947be7208cba60ad95270a4da7 (diff)
downloadpoezio-91b960b797bbf17f6c4b33279f2d406c5a2c93b2.tar.gz
poezio-91b960b797bbf17f6c4b33279f2d406c5a2c93b2.tar.bz2
poezio-91b960b797bbf17f6c4b33279f2d406c5a2c93b2.tar.xz
poezio-91b960b797bbf17f6c4b33279f2d406c5a2c93b2.zip
Handle I/O errors better
- Do not crash because of low disk space - Notify the user whenever it happens - A few functions now return a boolean instead of nothing - Config.silent_set is Config.set_and_save without toggle and returning strings. It is used whenever we don’t need set_and_save - Config.set_and_save now returns a tuple (that can be passed directly to core.information()) TODO: display the precise error to the user (instead of “unable to…”)
-rw-r--r--src/config.py33
-rw-r--r--src/core.py36
-rw-r--r--src/logger.py27
-rw-r--r--src/roster.py2
-rw-r--r--src/tabs.py18
5 files changed, 81 insertions, 35 deletions
diff --git a/src/config.py b/src/config.py
index e3c93f29..c94bb89a 100644
--- a/src/config.py
+++ b/src/config.py
@@ -12,6 +12,8 @@ from/to the config file
DEFSECTION = "Poezio"
+from gettext import gettext as _
+
from configparser import RawConfigParser, NoOptionError, NoSectionError
from os import environ, makedirs, path
from shutil import copy2
@@ -171,10 +173,16 @@ class Config(RawConfigParser):
result_lines.append('%s = %s' % (option, value))
- df = open(self.file_name, 'w', encoding='utf-8')
- for line in result_lines:
- df.write('%s\n' % line)
- df.close()
+ try:
+ df = open(self.file_name, 'w', encoding='utf-8')
+ for line in result_lines:
+ df.write('%s\n' % line)
+ df.close()
+ except:
+ success = False
+ else:
+ success = True
+ return success
def set_and_save(self, option, value, section=DEFSECTION):
"""
@@ -191,15 +199,26 @@ class Config(RawConfigParser):
elif current.lower() == "true":
value = "false"
else:
- return "Could not toggle option: %s. Current value is %s." % (option, current or "empty")
+ return (_("Could not toggle option: %s. Current value is %s.") % (option, current or _("empty")), 'Warning')
if self.has_section(section):
RawConfigParser.set(self, section, option, value)
else:
self.add_section(section)
RawConfigParser.set(self, section, option, value)
- self.write_in_file(section, option, value)
- return "%s=%s" % (option, value)
+ if not self.write_in_file(section, option, value):
+ return (_('Unable to write in the config file'), 'Error')
+ return ("%s=%s" % (option, value), 'Info')
+ def silent_set(self, option, value, section=DEFSECTION):
+ """
+ Set a value, save, and return True on success and False on failure
+ """
+ if self.has_section(section):
+ RawConfigParser.set(self, section, option, value)
+ else:
+ self.add_section(section)
+ RawConfigParser.set(self, section, option, value)
+ return self.write_in_file(section, option, value)
def set(self, option, value, section=DEFSECTION):
"""
diff --git a/src/core.py b/src/core.py
index 97470b48..68c7f241 100644
--- a/src/core.py
+++ b/src/core.py
@@ -432,8 +432,9 @@ class Core(object):
"""
Save config in the file just before exit
"""
- roster.save_to_config_file()
- config.set_and_save('info_win_height', self.information_win_size, 'var')
+ if not roster.save_to_config_file() or \
+ not config.silent_set('info_win_height', self.information_win_size, 'var'):
+ self.information(_('Unable to write in the config file'), 'Error')
def on_roster_enter_key(self, roster_row):
"""
@@ -595,8 +596,9 @@ class Core(object):
"""
self.status = Status(show=pres, message=msg)
if config.get('save_status', 'true').lower() != 'false':
- config.set_and_save('status', pres if pres else '')
- config.set_and_save('status_message', msg.replace('\n', '|') if msg else '')
+ if not config.silent_set('status', pres if pres else '') or \
+ not config.silent_set('status_message', msg.replace('\n', '|') if msg else ''):
+ self.information(_('Unable to write in the config file'), 'Error')
def get_bookmark_nickname(self, room_name):
"""
@@ -1238,7 +1240,8 @@ class Core(object):
Enable/disable the left panel.
"""
enabled = config.get('enable_vertical_tab_list', 'false')
- config.set_and_save('enable_vertical_tab_list', 'false' if enabled == 'true' else 'true')
+ if not config.silent_set('enable_vertical_tab_list', 'false' if enabled == 'true' else 'true'):
+ self.information(_('Unable to write in the config file'), 'Error')
self.call_for_resize()
def resize_global_information_win(self):
@@ -2051,7 +2054,7 @@ class Core(object):
path = os.path.expanduser(value)
self.plugin_manager.on_plugins_conf_dir_change(path)
self.call_for_resize()
- self.information(info, "Info")
+ self.information(*info)
def completion_set(self, the_input):
"""Completion for /set"""
@@ -2336,7 +2339,8 @@ class Core(object):
return self.command_help('bind')
elif len(args) < 2:
args.append("")
- config.set_and_save(args[0], args[1], section='bindings')
+ if not config.silent_set(args[0], args[1], section='bindings'):
+ self.information(_('Unable to write in the config file'), 'Error')
if args[1]:
self.information('%s is now bound to %s' % (args[0], args[1]), 'Info')
else:
@@ -2716,7 +2720,8 @@ class Core(object):
conversation.remote_wants_chatstates = True
else:
conversation.remote_wants_chatstates = False
- logger.log_message(jid.bare, remote_nick, body)
+ if not logger.log_message(jid.bare, remote_nick, body):
+ self.information(_('Unable to write in the log file'), 'Error')
if 'private' in config.get('beep_on', 'highlight private').split():
if config.get_by_tabname('disable_beep', 'false', jid.bare, False).lower() != 'true':
curses.beep()
@@ -2967,7 +2972,8 @@ class Core(object):
if 'private' in config.get('beep_on', 'highlight private').split():
if config.get_by_tabname('disable_beep', 'false', jid.full, False).lower() != 'true':
curses.beep()
- logger.log_message(jid.full.replace('/', '\\'), nick_from, body)
+ if not logger.log_message(jid.full.replace('/', '\\'), nick_from, body):
+ self.information(_('Unable to write in the log file'), 'Error')
if tab is self.current_tab():
self.refresh_window()
else:
@@ -3147,7 +3153,8 @@ class Core(object):
if presence.match('presence/muc') or presence.xml.find('{http://jabber.org/protocol/muc#user}x'):
return
jid = presence['from']
- logger.log_roster_change(jid.bare, 'got offline')
+ if not logger.log_roster_change(jid.bare, 'got offline'):
+ self.information(_('Unable to write in the log file'), 'Error')
# If a resource got offline, display the message in the conversation with this
# precise resource.
if jid.resource:
@@ -3168,7 +3175,8 @@ class Core(object):
if contact is None:
# Todo, handle presence coming from contacts not in roster
return
- logger.log_roster_change(jid.bare, 'got online')
+ if not logger.log_roster_change(jid.bare, 'got online'):
+ self.information(_('Unable to write in the log file'), 'Error')
resource = Resource(jid.full, {
'priority': presence.get_priority() or 0,
'status': presence['status'],
@@ -3430,13 +3438,15 @@ class Core(object):
if input.value:
self.information('Setting new certificate: old: %s, new: %s' % (cert, found_cert), 'Info')
log.debug('Setting certificate to %s', found_cert)
- config.set_and_save('certificate', found_cert)
+ if not config.silent_set('certificate', found_cert):
+ self.information(_('Unable to write in the config file'), 'Error')
else:
self.information('You refused to validate the certificate. You are now disconnected', 'Info')
self.xmpp.disconnect()
else:
log.debug('First time. Setting certificate to %s', found_cert)
- config.set_and_save('certificate', found_cert)
+ if not config.silent_set('certificate', found_cert):
+ self.information(_('Unable to write in the config file'), 'Error')
diff --git a/src/logger.py b/src/logger.py
index 8b4b1d3c..a696137f 100644
--- a/src/logger.py
+++ b/src/logger.py
@@ -32,7 +32,10 @@ class Logger(object):
def __del__(self):
for opened_file in self.fds.values():
if opened_file:
- opened_file.close()
+ try:
+ opened_file.close()
+ except: # Can't close? too bad
+ pass
def reload_all(self):
"""Close and reload all the file handles (on SIGHUP)"""
@@ -106,7 +109,7 @@ class Logger(object):
else:
fd = self.check_and_create_log_dir(jid)
if not fd:
- return
+ return True
try:
msg = clean_text(msg)
if date is None:
@@ -117,18 +120,26 @@ class Logger(object):
fd.write(''.join((str_time, nick, ': ', msg, '\n')))
else:
fd.write(''.join((str_time, '* ', msg, '\n')))
- except IOError:
- pass
+ except:
+ return False
else:
- fd.flush() # TODO do something better here?
+ try:
+ fd.flush() # TODO do something better here?
+ except:
+ return False
+ return True
def log_roster_change(self, jid, message):
if not self.roster_logfile:
try:
self.roster_logfile = open(os.path.join(DATA_HOME, 'logs', 'roster.log'), 'a')
except IOError:
- return
- self.roster_logfile.write('%s %s %s\n' % (datetime.now().strftime('%d-%m-%y [%H:%M:%S]'), jid, message))
- self.roster_logfile.flush()
+ return False
+ try:
+ self.roster_logfile.write('%s %s %s\n' % (datetime.now().strftime('%d-%m-%y [%H:%M:%S]'), jid, message))
+ self.roster_logfile.flush()
+ except:
+ return False
+ return True
logger = Logger()
diff --git a/src/roster.py b/src/roster.py
index 67e81da9..b0f3cf65 100644
--- a/src/roster.py
+++ b/src/roster.py
@@ -141,7 +141,7 @@ class Roster(object):
folded_groups = ':'.join([group.name for group in self.groups.values()\
if group.folded])
log.debug('folded:%s\n' %folded_groups)
- config.set_and_save('folded_roster_groups', folded_groups, 'var')
+ return config.silent_set('folded_roster_groups', folded_groups, 'var')
def get_nb_connected_contacts(self):
"""
diff --git a/src/tabs.py b/src/tabs.py
index bbae6e3d..ef31da67 100644
--- a/src/tabs.py
+++ b/src/tabs.py
@@ -481,7 +481,8 @@ class ChatTab(Tab):
"""
Log the messages in the archives.
"""
- logger.log_message(self.name, nickname, txt, date=time)
+ if not logger.log_message(self.name, nickname, txt, date=time):
+ self.core.information(_('Unable to write in the log file'), 'Error')
def add_message(self, txt, time=None, nickname=None, forced_user=None, nick_color=None, identifier=None):
self._text_buffer.add_message(txt, time=time,
@@ -1696,7 +1697,8 @@ class MucTab(ChatTab):
to be
"""
if time is None and self.joined: # don't log the history messages
- logger.log_message(self.name, nickname, txt)
+ if not logger.log_message(self.name, nickname, txt):
+ self.core.information(_('Unable to write in the log file'), 'Error')
def do_highlight(self, txt, time, nickname):
"""
@@ -1844,7 +1846,8 @@ class PrivateTab(ChatTab):
msg = self.core.xmpp.make_message(self.get_name())
msg['type'] = 'chat'
msg['body'] = line
- logger.log_message(self.get_name().replace('/', '\\'), self.own_nick, line)
+ if not logger.log_message(self.get_name().replace('/', '\\'), self.own_nick, line):
+ self.core.information(_('Unable to write in the log file'), 'Error')
# trigger the event BEFORE looking for colors.
# This lets a plugin insert \x19xxx} colors, that will
# be converted in xhtml.
@@ -2722,9 +2725,11 @@ class RosterInfoTab(Tab):
"""
option = 'roster_show_offline'
if config.get(option, 'false') == 'false':
- config.set_and_save(option, 'true')
+ success = config.silent_set(option, 'true')
else:
- config.set_and_save(option, 'false')
+ success = config.silent_set(option, 'false')
+ if not success:
+ self.information(_('Unable to write in the config file'), 'Error')
return True
def on_slash(self):
@@ -3036,7 +3041,8 @@ class ConversationTab(ChatTab):
self.core.events.trigger('conversation_say_after', msg, self)
self.last_sent_message = msg
msg.send()
- logger.log_message(safeJID(self.get_dest_jid()).bare, self.core.own_nick, line)
+ if not logger.log_message(safeJID(self.get_dest_jid()).bare, self.core.own_nick, line):
+ self.core.information(_('Unable to write in the log file'), 'Error')
self.cancel_paused_delay()
self.text_win.refresh()
self.input.refresh()