diff --git a/sublime_evernote.py b/sublime_evernote.py
index 92a3f59..fdbb9b2 100644
--- a/sublime_evernote.py
+++ b/sublime_evernote.py
@@ -17,12 +17,13 @@
sys.path.append(lib_path)
import evernote.edam.type.ttypes as Types
-import evernote.edam.error.ttypes as Errors
+from evernote.edam.error.ttypes import EDAMErrorCode, EDAMUserException, EDAMSystemException, EDAMNotFoundException
# import evernote.edam.userstore.UserStore as UserStore
import evernote.edam.notestore.NoteStore as NoteStore
import thrift.protocol.TBinaryProtocol as TBinaryProtocol
import thrift.transport.THttpClient as THttpClient
+from socket import gaierror
import sublime
import sublime_plugin
@@ -123,6 +124,72 @@ def datestr(d):
return d.strftime("on %d/%m/%y")
+ecode = EDAMErrorCode
+error_groups = {
+ 'server': ('Internal server error', [ecode.UNKNOWN, ecode.INTERNAL_ERROR, ecode.SHARD_UNAVAILABLE, ecode.UNSUPPORTED_OPERATION ]),
+ 'data': ('User supplied data is invalid or conflicting', [ecode.BAD_DATA_FORMAT, ecode.DATA_REQUIRED, ecode.DATA_CONFLICT, ecode.LEN_TOO_SHORT, ecode.LEN_TOO_LONG, ecode.TOO_FEW, ecode.TOO_MANY]),
+ 'permission': ('Action not allowed, permission denied or limits exceeded', [ecode.PERMISSION_DENIED, ecode.LIMIT_REACHED, ecode.QUOTA_REACHED, ecode.TAKEN_DOWN, ecode.RATE_LIMIT_REACHED]),
+ 'auth': ('Authorisation error, consider re-configuring the plugin', [ecode.INVALID_AUTH, ecode.AUTH_EXPIRED]),
+ 'contents': ('Illegal note contents', [ecode.ENML_VALIDATION])
+ }
+
+
+def errcode2name(err):
+ name = ecode._VALUES_TO_NAMES.get(err.errorCode, "UNKNOWN")
+ name = name.replace("_", " ").capitalize()
+ return name
+
+
+def err_reason(err):
+ for reason, group in error_groups.values():
+ if err.errorCode in group:
+ return reason
+ return "Unknown reason"
+
+
+def explain_error(err):
+ if isinstance(err, EDAMUserException):
+ print("Evernote error: [%s] %s" % (errcode2name(err), err.parameter))
+ if err.errorCode in error_groups["contents"][1]:
+ explanation = "The contents of the note are not valid.\n"
+ msg = err.parameter.split('"')
+ what = msg[0].strip().lower()
+ if what == "element type":
+ return explanation +\
+ "The inline HTML tag '%s' is not allowed in Evernote notes." %\
+ msg[1]
+ elif what == "attribute":
+ if msg[1] == "class":
+ return explanation +\
+ "The note contains a '%s' HTML tag "\
+ "with a 'class' attribute; this is not allowed in a note.\n"\
+ "Please use inline 'style' attributes or customise "\
+ "the 'inline_css' setting." %\
+ msg[3]
+ else:
+ return explanation +\
+ "The note contains a '%s' HTML tag"\
+ " with a '%s' attribute; this is not allowed in a note." %\
+ msg[3], msg[1]
+ return explanation + err.parameter
+ else:
+ return err_reason(err)
+ elif isinstance(err, EDAMSystemException):
+ print("Evernote error: [%s] %s" % (errcode2name(err), err.message))
+ return "Evernote cannot perform the requested action:\n" + err_reason(err)
+ elif isinstance(err, EDAMNotFoundException):
+ print("Evernote error: [%s = %s] Not found" % (err.identifier, err.key))
+ return "Cannot find %s" % err.identifier.split('.', 1)[0]
+ elif isinstance(err, gaierror):
+ print("Evernote error: [socket] %s" % str(err))
+ return 'The Evernote services seem unreachable.\n'\
+ 'Please check your connection and retry.'
+ else:
+ print("Evernote plugin error: %s" % str(err))
+ return 'Evernote plugin error, please contact developer at\n'\
+ 'https://github.com/bordaigorl/sublime-evernote/issues'
+
+
class EvernoteDo():
_noteStore = None
@@ -235,7 +302,9 @@ def get_notebooks(self):
if self.settings.get("sort_notebooks"):
notebooks.sort(key=lambda nb: nb.name)
except Exception as e:
- sublime.error_message('Error getting notebooks: %s' % e)
+ sublime.error_message(explain_error(e))
+ LOG(e)
+ return []
EvernoteDo._notebook_by_name = dict([(nb.name, nb) for nb in notebooks])
EvernoteDo._notebook_by_guid = dict([(nb.guid, nb) for nb in notebooks])
EvernoteDo._notebooks_cache = notebooks
@@ -456,15 +525,17 @@ def __send_note(notebookGuid):
view.set_syntax_file(self.md_syntax)
self.message("Successfully posted note: guid:%s" % cnote.guid, 10000)
self.update_status_info(cnote)
- except Errors.EDAMUserException as e:
+ except EDAMUserException as e:
args = dict(title=note.title, notebookGuid=note.notebookGuid, tags=note.tagNames)
if e.errorCode == 9:
self.connect(self.do_send, **args)
else:
- if sublime.ok_cancel_dialog('Evernote complained:\n\n%s\n\nRetry?' % e.parameter):
+ if sublime.ok_cancel_dialog('Evernote complained:\n\n%s\n\nRetry?' % explain_error(err)):
self.connect(self.do_send, **args)
+ except EDAMSystemException as e:
+ sublime.error_message('Evernote error:\n%s' % explain_error(err))
except Exception as e:
- sublime.error_message('Error %s' % e)
+ sublime.error_message('Evernote plugin error %s' % e)
choose_title()
@@ -490,14 +561,9 @@ def __update_note():
self.view.settings().set("$evernote_title", cnote.title)
self.message("Successfully updated note: guid:%s" % cnote.guid)
self.update_status_info(cnote)
- except Errors.EDAMUserException as e:
- if e.errorCode == 9:
- self.connect(self.__update_note)
- else:
- if sublime.ok_cancel_dialog('Evernote complained:\n\n%s\n\nRetry?' % e.parameter):
- self.connect(self.__update_note)
except Exception as e:
- sublime.error_message('Error %s' % e)
+ if sublime.ok_cancel_dialog('Evernote complained:\n\n%s\n\nRetry?' % explain_error(e)):
+ self.connect(self.__update_note)
__update_note()
@@ -635,10 +701,8 @@ def open_note(self, guid, convert=True, **unk_args):
newview.show(0)
self.message('Note "%s" opened!' % note.title)
self.update_status_info(note, newview)
- except Errors.EDAMNotFoundException as e:
- sublime.error_message("The note with the specified guid could not be found.")
- except Errors.EDAMUserException:
- sublime.error_message("The specified note could not be found.\nPlease check the guid is correct.")
+ except Exception as e:
+ sublime.error_message(explain_error(e))
class AttachToEvernoteNote(OpenEvernoteNoteCommand):
@@ -695,11 +759,9 @@ def open_note(self, guid, insert_in_content=True, filename=None, prompt=False, *
'' % (mime, h.hexdigest())
note.resources = resources
noteStore.updateNote(self.token(), note)
- self.message("Succesfully attached to note '%s'" % note.title)
- except Errors.EDAMNotFoundException as e:
- sublime.error_message("The note with the specified guid could not be found.")
- except Errors.EDAMUserException:
- sublime.error_message("The specified note could not be found.\nPlease check the guid is correct.")
+ self.message("Successfully attached to note '%s'" % note.title)
+ except Exception as e:
+ sublime.error_message(explain_error(e))
def is_enabled(self, insert_in_content=True, filename=None, **unk):
return filename is not None or self.window.active_view() is not None
@@ -719,45 +781,50 @@ def do_run(self, edit, insert_in_content=True, filename=None, prompt=False):
None, None)
return
filename = filename.strip()
- filecontents = None
attr = {}
- if filename.startswith("http://") or \
- filename.startswith("https://"):
- # download
- import urllib.request
- response = urllib.request.urlopen(filename)
- filecontents = response.read()
- attr = {"sourceURL": filename}
- else:
- datafile = os.path.expanduser(filename)
- if os.path.exists(datafile):
+ try:
+ if filename.startswith("http://") or \
+ filename.startswith("https://"):
+ # download
+ import urllib.request
+ response = urllib.request.urlopen(filename)
+ filecontents = response.read()
+ attr = {"sourceURL": filename}
+ else:
+ datafile = os.path.expanduser(filename)
with open(datafile, 'rb') as content_file:
filecontents = content_file.read()
- attr = {"fileName": os.path.basename(datafile)}
-
- if filecontents is None:
- sublime.error_message("The specified file/URL could not be found!")
+ attr = {"fileName": os.path.basename(datafile)}
+ except Exception as e:
+ sublime.error_message(
+ "Evernote plugin has troubles locating the specified file/URL.\n" +
+ explain_error(e))
return
- guid = self.view.settings().get("$evernote_guid")
- noteStore = self.get_note_store()
- note = noteStore.getNote(self.token(), guid, False, False, False, False)
- mime = mimetypes.guess_type(filename)[0] or "application/octet-stream"
- h = hashlib.md5(filecontents)
- attachment = Types.Resource(
- # noteGuid=guid,
- mime=mime,
- data=Types.Data(body=filecontents, size=len(filecontents), bodyHash=h.digest()),
- attributes=Types.ResourceAttributes(attachment=not insert_in_content, **attr))
- resources = note.resources or []
- resources.append(attachment)
- note.resources = resources
- self.message("Uploading attachment...")
- noteStore.updateNote(self.token(), note)
- if insert_in_content:
- view.insert(edit, view.sel()[0].a,
- '' % (mime, h.hexdigest()))
- sublime.set_timeout(lambda: view.run_command("save_evernote_note"), 10)
+ try:
+ guid = self.view.settings().get("$evernote_guid")
+ noteStore = self.get_note_store()
+ note = noteStore.getNote(self.token(), guid, False, False, False, False)
+ mime = mimetypes.guess_type(filename)[0] or "application/octet-stream"
+ h = hashlib.md5(filecontents)
+ attachment = Types.Resource(
+ # noteGuid=guid,
+ mime=mime,
+ data=Types.Data(body=filecontents, size=len(filecontents), bodyHash=h.digest()),
+ attributes=Types.ResourceAttributes(attachment=not insert_in_content, **attr))
+ resources = note.resources or []
+ resources.append(attachment)
+ note.resources = resources
+ self.message("Uploading attachment...")
+ noteStore.updateNote(self.token(), note)
+ if insert_in_content:
+ view.insert(edit, view.sel()[0].a,
+ '' % (mime, h.hexdigest()))
+ sublime.set_timeout(lambda: view.run_command("save_evernote_note"), 10)
+ except Exception as e:
+ sublime.error_message(
+ "Evernote plugin cannot insert the attachment.\n" +
+ explain_error(e))
def is_enabled(self):
if self.view.settings().get("$evernote_guid", False):
@@ -813,8 +880,8 @@ def on_done2(i):
else:
open_file_with_app(tmp)
except Exception as e:
- sublime.error_message("Unable to fetch the attachment.")
- print(e)
+ sublime.error_message(
+ "Unable to fetch the attachment.\n%s" % explain_error(e))
if menu:
self.view.window().show_quick_panel(menu, on_done)