diff --git a/idaplugin/rematch/actions/base.py b/idaplugin/rematch/actions/base.py index 49809eba5..dc1de6c5a 100755 --- a/idaplugin/rematch/actions/base.py +++ b/idaplugin/rematch/actions/base.py @@ -4,25 +4,37 @@ import idc -class Action(idaapi.action_handler_t): - """Actions are objects registered to IDA's interface and added to the - rematch menu and toolbar""" - dialog = None - +class Action(): reject_handler = None finish_handler = None submit_handler = None response_handler = None exception_handler = None - def __init__(self): + def __init__(self, ui_class): + self.ui_class = ui_class + self.ui = None + + def __repr__(self): + return "".format(self.ui_class) + + def running(self): + return self.ui is not None + + +class IDAAction(idaapi.action_handler_t, Action): + """Actions are objects registered to IDA's interface and added to the + rematch menu and toolbar""" + + def __init__(self, *args, **kwargs): + super(IDAAction, self).__init__(*args, **kwargs) self._icon = None - self.dlg = None def __repr__(self): - return "".format(self.get_id()) + return "".format(self.get_id(), self.ui_class) def __del__(self): + super(IDAAction, self).__del__() if self._icon: idaapi.free_custom_icon(self._icon) @@ -81,23 +93,20 @@ def get_action_path(self): return '/'.join(t) - @classmethod - def register(cls): - action = cls() - r = idaapi.register_action(action.get_desc()) + def register(self): + r = idaapi.register_action(self.get_desc()) if not r: - log('actions').warn("failed registering %s: %s", cls, r) + log('actions').warn("failed registering %s: %s", self, r) return idaapi.attach_action_to_menu( - action.get_action_path(), - action.get_id(), + self.get_action_path(), + self.get_id(), idaapi.SETMENU_APP) r = idaapi.attach_action_to_toolbar( "AnalysisToolBar", - action.get_id()) + self.get_id()) if not r: - log('actions').warn("registration of %s failed: %s", cls, r) - return action + log('actions').warn("registration of %s failed: %s", self, r) def update(self, ctx): return idaapi.AST_ENABLE if self.enabled(ctx) else idaapi.AST_DISABLE @@ -107,25 +116,22 @@ def activate(self, ctx): if self.running(): return - if callable(self.dialog): - self.dlg = self.dialog(reject_handler=self.reject_handler, - submit_handler=self.submit_handler, - response_handler=self.response_handler, - exception_handler=self.exception_handler) + if callable(self.ui_class): + self.ui = self.ui_class(reject_handler=self.reject_handler, + submit_handler=self.submit_handler, + response_handler=self.response_handler, + exception_handler=self.exception_handler) if self.finish_handler: - self.dlg.finished.connect(self.finish_handler) - self.dlg.finished.connect(self.close_dialog) - self.dlg.finished.connect(self.force_update) - self.dlg.show() + self.ui.finished.connect(self.finish_handler) + self.ui.finished.connect(self.close_dialog) + self.ui.finished.connect(self.force_update) + self.ui.show() else: log('actions').warn("%s: no activation", self.__class__) - def running(self): - return self.dlg is not None - def close_dialog(self): - del self.dlg - self.dlg = None + del self.ui + self.ui = None @staticmethod def force_update(): @@ -136,7 +142,7 @@ def force_update(): idaapi.request_refresh(iwid_all) -class IdbAction(Action): +class IdbAction(IDAAction): """This action is only available when an idb file is loaded""" @staticmethod def enabled(ctx): @@ -144,7 +150,7 @@ def enabled(ctx): return bool(idc.GetIdbPath()) -class UnauthAction(Action): +class UnauthAction(IDAAction): """This action is only available when a user is logged off""" @staticmethod def enabled(ctx): @@ -152,7 +158,7 @@ def enabled(ctx): return not bool(user['is_authenticated']) -class AuthAction(Action): +class AuthAction(IDAAction): """This action is only available when a user is logged in""" @staticmethod def enabled(ctx): diff --git a/idaplugin/rematch/actions/login.py b/idaplugin/rematch/actions/login.py index a235ddb4e..7799b220d 100755 --- a/idaplugin/rematch/actions/login.py +++ b/idaplugin/rematch/actions/login.py @@ -3,16 +3,13 @@ from .. import config from .. import exceptions -from ..dialogs.login import LoginDialog - class LoginAction(base.UnauthAction): name = "&Login" group = "User" - dialog = LoginDialog - def __init__(self): - super(LoginAction, self).__init__() + def __init__(self, *args, **kwargs): + super(LoginAction, self).__init__(*args, **kwargs) self.username = None self.password = None self.server = None @@ -34,8 +31,8 @@ def submit_handler(self, username, password, server, remember): def handle_login(self, response): del response - self.dlg.statusLbl.setText("Connected!") - self.dlg.statusLbl.setStyleSheet("color: green;") + self.ui.statusLbl.setText("Connected!") + self.ui.statusLbl.setStyleSheet("color: green;") config['login']['username'] = self.username config['login']['server'] = self.server @@ -45,17 +42,17 @@ def handle_login(self, response): config['login']['password'] = "" config.save() - self.dlg.accept() + self.ui.accept() def handle_exception(self, exception): if isinstance(exception, (exceptions.ConnectionException, exceptions.ServerException)): - self.dlg.statusLbl.setText("Connection to server failed.") - self.dlg.statusLbl.setStyleSheet("color: blue;") + self.ui.statusLbl.setText("Connection to server failed.") + self.ui.statusLbl.setStyleSheet("color: blue;") elif isinstance(exception, (exceptions.QueryException, exceptions.AuthenticationException)): - self.dlg.statusLbl.setText("Invalid user name or password.") - self.dlg.statusLbl.setStyleSheet("color: red;") + self.ui.statusLbl.setText("Invalid user name or password.") + self.ui.statusLbl.setStyleSheet("color: red;") class LogoutAction(base.AuthAction): diff --git a/idaplugin/rematch/actions/project.py b/idaplugin/rematch/actions/project.py index 4906d2fa4..be1885677 100755 --- a/idaplugin/rematch/actions/project.py +++ b/idaplugin/rematch/actions/project.py @@ -1,5 +1,4 @@ from . import base -from ..dialogs.project import AddProjectDialog, AddFileDialog from .. import netnode from .. import network @@ -8,7 +7,6 @@ class AddProjectAction(base.AuthAction): name = "&Add project" group = "Project" - dialog = AddProjectDialog @staticmethod def submit_handler(name, description, private, bind_current): @@ -31,7 +29,6 @@ def response_handler(cls, response): class AddFileAction(base.UnboundFileAction): name = "&Add file" group = "Project" - dialog = AddFileDialog @staticmethod def submit_handler(project, name, md5hash, description, shareidb): diff --git a/idaplugin/rematch/actions/settings.py b/idaplugin/rematch/actions/settings.py index d1b4bdb89..fcb9b41db 100755 --- a/idaplugin/rematch/actions/settings.py +++ b/idaplugin/rematch/actions/settings.py @@ -3,12 +3,9 @@ from . import base from .. import config -from ..dialogs.settings import SettingsDialog - -class SettingsAction(base.Action): +class SettingsAction(base.IDAAction): name = "&Settings" - dialog = SettingsDialog @staticmethod def submit_handler(autocheck, autoupdate, autologin, autologout, debug): diff --git a/idaplugin/rematch/plugin.py b/idaplugin/rematch/plugin.py index ad8208227..98ad74fb6 100755 --- a/idaplugin/rematch/plugin.py +++ b/idaplugin/rematch/plugin.py @@ -4,6 +4,7 @@ from . import config, user from . import actions +from . import dialogs from . import update @@ -47,15 +48,16 @@ def setup(self): self.menu = QtWidgets.QMenu("Rematch") self.get_mainwindow().menuWidget().addMenu(self.menu) - actions.login.LoginAction.register() - actions.login.LogoutAction.register() + actions.login.LoginAction(dialogs.login.LoginDialog).register() + actions.login.LogoutAction(None).register() - actions.project.AddProjectAction.register() - actions.project.AddFileAction.register() + actions.project.AddProjectAction(dialogs.project. + AddProjectDialog).register() + actions.project.AddFileAction(dialogs.project.AddFileDialog).register() - actions.match.MatchAction.register() + actions.match.MatchAction(dialogs.match.MatchDialog).register() - actions.settings.SettingsAction.register() + actions.settings.SettingsAction(dialogs.settings.SettingsDialog).register() # set up status bar self.statusbar_label = QtWidgets.QLabel("Rematch loaded")