def execAccountingModules(received): """Execute all accounting modules in [reconfigured order Input: (dict) data received from client; (dict) internal parameters; (dict) reply items; Output: (bool) True - success; False - failure """ modulesOk = True for module in acctModules: if modulesOk and module.accountingCapable: modstr = '### Accounting module "%s" ###' % module.name info ('#' * len(modstr)) info (modstr) info ('#' * len(modstr)) try: # protect received data dictionary locReceived = received.copy() # execute acct function module['acct_funct'](locReceived) except: misc.printException() modulesOk = False else: # if everything was ok # assign probably changed attribute dictionaries to original ones misc.rewriteDict(received, locReceived) # exit cycle if any module failed else: break # return module execution result return modulesOk
def execFunction(function, received = None, check = None, reply = None): """Execute preloaded function Input: (function ref) reference to function, (dict) data received from client; (dict) internal parameters; (dict) reply items; Output: (mixed) function result """ ret = None try: # protect attribute dictionaries in case of failure locReceived = received.copy() locCheck = check.copy() locReply = reply.copy() ret = function(locReceived, locCheck, locReply) except: misc.printException() ret = None else: # if everything was ok # assign probably changed attribute dictionaries to original ones misc.rewriteDict(received, locReceived) misc.rewriteDict(check, locCheck) misc.rewriteDict(reply, locReply) return ret
def execShutdownModules(): """Execute all shutdown-capable modules Input: none Output: none """ for moduleName, module in loadedModules.items(): if module.shutdownCapable: try: module['shutdown_funct']() # catch all exceptions, report them to user and shutdown server except: misc.printException() misc.quit('Can not execute shutdown function in module "%s"' % moduleName, 1)
def editRPCServer(self, protocol, host, user, passwd, id): changed_RPC = False try: cursor = self.getCursor() cursor.execute( "UPDATE CUSTOM_RPC_SERVERS " "SET protocol = ?, host = ?, user = ?, pass = ?" "WHERE id = ?", (protocol, host, user, passwd, id)) changed_RPC = True except Exception as e: err_msg = 'error editing RPC server entry to DB' printException(getCallerName(), getFunctionName(), err_msg, e.args) finally: self.releaseCursor() if changed_RPC: self.app.sig_changed_rpcServers.emit()
def clearTable(self, table_name): cleared_RPC = False try: cursor = self.getCursor() cursor.execute("DELETE FROM %s" % table_name) # in case, reload default RPC and emit changed signal if table_name == 'CUSTOM_RPC_SERVERS': self.initTable_RPC(cursor) cleared_RPC = True except Exception as e: err_msg = 'error clearing %s in database' % table_name printException(getCallerName(), getFunctionName(), err_msg, e.args) finally: self.releaseCursor(vacuum=True) if cleared_RPC: self.app.sig_changed_rpcServers.emit()
def process_blockbook_exceptions_int(*args, **kwargs): client = args[0] try: return func(*args, **kwargs) except Exception as e: if client.isTestnet: new_url = "https://testnet.pivx.link" else: new_url = "https://explorer.pivx.link" message = "BlockBook Client exception on %s\nTrying backup server %s" % (client.url, new_url) printException(getCallerName(True), getFunctionName(True), message, str(e)) try: client.url = new_url return func(*args, **kwargs) except Exception: raise
def addReward(self, utxo): logging.debug("DB: Adding reward") try: cursor = self.getCursor() cursor.execute( "INSERT OR REPLACE INTO UTXOS " "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", (utxo['txid'], utxo['vout'], utxo['satoshis'], utxo['confirmations'], utxo['script'], utxo['receiver'], utxo['coinstake'], utxo['staker'])) except Exception as e: err_msg = 'error adding reward UTXO to DB' printException(getCallerName(), getFunctionName(), err_msg, e) finally: self.releaseCursor()
def signature1(self, device): try: fNewSigs = NewSigsActive(self.currHeight, self.isTestnet) if fNewSigs: serializedData = self.getNewBroadcastMessage() else: serializedData = self.getOldBroadcastMessage() printDbg("SerializedData: %s" % serializedData) # HW wallet signature device.signMess(self.tab_main.caller, self.nodePath, serializedData, self.isTestnet) #wait for signal when device.sig1 is ready then --> finalizeStartMessage except Exception as e: err_msg = "error in signature1" printException(getCallerName(), getFunctionName(), err_msg, e.args) except KeyboardInterrupt: err_msg = "Keyboard Interrupt" printException(getCallerName(), getFunctionName(), err_msg, '') return None
def __init__(self): # Lock for threads self.lock = threading.Lock() self.rpc_ip, self.rpc_port, self.rpc_user, self.rpc_passwd = readRPCfile( ) rpc_url = "http://%s:%s@%s:%d" % (self.rpc_user, self.rpc_passwd, self.rpc_ip, self.rpc_port) try: self.lock.acquire() self.conn = AuthServiceProxy(rpc_url, timeout=120) except JSONRPCException as e: err_msg = 'remote or local PIVX-cli running?' printException(getCallerName(), getFunctionName(), err_msg, e) except Exception as e: err_msg = 'remote or local PIVX-cli running?' printException(getCallerName(), getFunctionName(), err_msg, e) finally: self.lock.release()
def onCheckAllMN(self): if not self.caller.rpcConnected: myPopUp_sb(self.caller, "crit", 'SPMT - hw device check', "RPC server must be connected to perform this action.") printDbg("Unable to connect: %s" % self.caller.rpcStatusMess) return if self.caller.masternode_list is None or self.caller.masternode_list == []: myPopUp_sb(self.caller, "crit", 'SPMT - Check-All masternodes', "No masternode in list. Add masternodes first.") return try: printDbg("Check-All pressed") ThreadFuns.runInThread(self.updateAllMasternodes_thread, (), self.displayMNlistUpdated) except Exception as e: err_msg = "error in checkAllMN" printException(getCallerName(), getFunctionName(), err_msg, e)
def ParseTxOutput(p, isTestnet=False): vout = {} vout["value"] = p.readInt(8, "little") script_len = p.readInt(1, "little") vout["scriptPubKey"] = {} vout["scriptPubKey"]["hex"] = p.readString(script_len, "big") vout["scriptPubKey"]["addresses"] = [] try: locking_script = bytes.fromhex(vout["scriptPubKey"]["hex"]) # add addresses only if P2PKH, P2PK or P2CS if len(locking_script) in [25, 35, 51]: add_bytes = utils.extract_pkh_from_locking_script(locking_script) address = pubkeyhash_to_address(add_bytes, isTestnet) vout["scriptPubKey"]["addresses"].append(address) except Exception as e: printException(getCallerName(True), getFunctionName(True), "error parsing output", str(e)) return vout
def addProposal(self, p): logging.debug("DB: Adding proposal") try: cursor = self.getCursor() cursor.execute( "INSERT OR REPLACE INTO PROPOSALS " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (p.name, p.URL, p.Hash, p.FeeHash, p.BlockStart, p.BlockEnd, p.TotalPayCount, p.RemainingPayCount, p.PaymentAddress, p.Yeas, p.Nays, p.Abstains, p.ToalPayment, p.MonthlyPayment)) except Exception as e: err_msg = 'error adding proposal to DB' printException(getCallerName(), getFunctionName(), err_msg, e) finally: self.releaseCursor()
def getReward(self, tx_hash, tx_ouput_n): logging.debug("DB: Getting reward") try: cursor = self.getCursor() cursor.execute( "SELECT * FROM REWARDS" " WHERE tx_hash = ? AND tx_ouput_n = ?", (tx_hash, tx_ouput_n)) rows = cursor.fetchall() except Exception as e: err_msg = 'error getting reward %s-%d' % (tx_hash, tx_ouput_n) printException(getCallerName(), getFunctionName(), err_msg, e) rows = [] finally: self.releaseCursor() return self.rewards_from_rows(rows)[0]
def vote_thread(self, ctrl, vote_code): if not isinstance(vote_code, int) or vote_code not in range(3): raise Exception("Wrong vote_code %s" % str(vote_code)) # Uncomment when needed # self.successVotes = 0 # self.failedVotes = 0 # save delay check data to cache self.caller.parent.cache[ "votingDelayCheck"] = self.ui.randomDelayCheck.isChecked() self.caller.parent.cache[ "votingDelayNeg"] = self.ui.randomDelayNeg_edt.value() self.caller.parent.cache[ "votingDelayPos"] = self.ui.randomDelayPos_edt.value() writeToFile(self.caller.parent.cache, cache_File) server_url = "http://{}:{}".format(self.caller.rpcClient.rpc_ip, self.caller.rpcClient.rpc_port) auth_pair = self.caller.rpcClient.rpc_user, self.caller.rpcClient.rpc_passwd for prop, mn in product(self.selectedTorrents, self.votingMasternodes): try: v_res = requests.post(url=server_url, auth=auth_pair, data=self.prepare_vote_data( prop.Hash, mn[1], ["ABSTAIN", "yes", "no"][vote_code])) response = json.loads(v_res.content) if 'error' in response: self.display_error(response['error']['message']) continue except Exception as e: printException( getCallerName(), getFunctionName(), 'Submitting a vote failed', e.args + (prop.Hash, mn[1], ["ABSTAIN", "yes", "no"][vote_code])) continue if self.ui.randomDelayCheck.isChecked(): time.sleep( random.randint(-int(self.ui.randomDelayNeg_edt.value()), int(self.ui.randomDelayPos_edt.value())))
def scanForAddress(self, account, spath, isTestnet=False): printOK("Scanning for Address n. %d on account n. %d" % (spath, account)) curr_path = MPATH + "%d'/0/%d" % (account, spath) self.lock.acquire() try: if not isTestnet: curr_addr = self.chip.getWalletPublicKey(curr_path).get('address')[12:-2] else: pubkey = compress_public_key(self.chip.getWalletPublicKey(curr_path).get('publicKey')).hex() curr_addr = pubkey_to_address(pubkey, isTestnet) except Exception as e: err_msg = 'error in scanForAddress' printException(getCallerName(), getFunctionName(), err_msg, e.args) return None finally: self.lock.release() return curr_addr
def getRewardsList(self, mn_name=None): try: cursor = self.getCursor() if mn_name is None: cursor.execute("SELECT * FROM REWARDS") else: cursor.execute("SELECT * FROM REWARDS WHERE mn_name = ?", (mn_name, )) rows = cursor.fetchall() except Exception as e: err_msg = 'error getting rewards list for masternode %s' % mn_name printException(getCallerName(), getFunctionName(), err_msg, e) rows = [] finally: self.releaseCursor() return self.rewards_from_rows(rows)
def getMyVotes(self, p_hash=None): try: cursor = self.getCursor() if p_hash is None: cursor.execute("SELECT * FROM MY_VOTES") else: cursor.execute("SELECT * FROM MY_VOTES WHERE p_hash = ?", (p_hash, )) rows = cursor.fetchall() except Exception as e: err_msg = 'error getting myVotes from DB' printException(getCallerName(), getFunctionName(), err_msg, e) rows = [] finally: self.releaseCursor() return self.myVotes_from_rows(rows)
def initDevice(self): try: if hasattr(self, 'dongle'): self.dongle.close() self.dongle = getDongle(False) printOK('Ledger Nano S drivers found') self.chip = btchip(self.dongle) printDbg("Ledger Initialized") self.initialized = True ver = self.chip.getFirmwareVersion() printOK("Ledger HW device connected [v. %s]" % str(ver.get('version'))) except Exception as e: err_msg = 'error Initializing Ledger' printException(getCallerName(), getFunctionName(), err_msg, e.args) self.initialized = False if hasattr(self, 'dongle'): self.dongle.close()
def getRawTx(self, tx_hash): logging.debug("DB: Getting rawtx for %s" % tx_hash) try: cursor = self.getCursor() cursor.execute("SELECT * FROM RAWTXES" " WHERE tx_hash = ?", (tx_hash, )) rows = cursor.fetchall() except Exception as e: err_msg = 'error getting raw tx for %s' % tx_hash printException(getCallerName(), getFunctionName(), err_msg, e) rows = [] finally: self.releaseCursor() if len(rows) > 0: return self.txes_from_rows(rows)[0] return None
def checkMN(self, ctrl): address = self.curr_masternode_address # Check rpc connection if not self.caller.rpcConnected: self.caller.myPopUp2(QMessageBox.Critical, 'SPMT - hw device check', "Connect to RPC server first") printDbg("Unable to connect: %s" % self.caller.rpcStatusMess) return None self.curr_statusData = self.caller.rpcClient.getMNStatus(address) try: if self.curr_statusData is not None: balance = self.apiClient.getBalance(address) self.curr_statusData['balance'] = balance except Exception as e: err_msg = "exception in checkMN" printException(getCallerName(), getFunctionName(), err_msg, e)
def signature1(self, device): self.sig_time = int(time.time()) serializedData = ipport(self.ip, self.port) serializedData += str(self.sig_time) serializedData += binascii.unhexlify(bitcoin.hash160(bytes.fromhex(self.collateral['pubKey'])))[::-1].hex() serializedData += binascii.unhexlify(bitcoin.hash160(bytes.fromhex(self.mnPubKey)))[::-1].hex() serializedData += str(self.protocol_version) printDbg("Masternode PubKey: %s" % self.mnPubKey) printDbg("SerializedData: MY_IP:%s" % serializedData.split(':')[1]) try: device.signMess(self.caller, self.nodePath, serializedData) #wait for signal when device.sig1 is ready then --> finalizeStartMessage except Exception as e: err_msg = "error in signature1" printException(getCallerName(), getFunctionName(), err_msg, e.args) except KeyboardInterrupt: err_msg = "Keyboard Interrupt" printException(getCallerName(), getFunctionName(), err_msg, e.args) return None
def addRPCServer(self, protocol, host, user, passwd): printDbg("DB: Adding new RPC server...") added_RPC = False try: cursor = self.getCursor() cursor.execute( "INSERT INTO CUSTOM_RPC_SERVERS (protocol, host, user, pass) " "VALUES (?, ?, ?, ?)", (protocol, host, user, passwd)) added_RPC = True printDbg("DB: RPC server added") except Exception as e: err_msg = 'error adding RPC server entry to DB' printException(getCallerName(), getFunctionName(), err_msg, e.args) finally: self.releaseCursor() if added_RPC: self.app.sig_changed_rpcServers.emit()
def updateRPCstatus(self, ctrl, fDebug=False): rpc_index, rpc_protocol, rpc_host, rpc_user, rpc_password = self.getRPCserver( ) if fDebug: printDbg("Trying to connect to RPC %s://%s..." % (rpc_protocol, rpc_host)) try: rpcClient = RpcClient(rpc_protocol, rpc_host, rpc_user, rpc_password) status, statusMess, lastBlock, r_time1, isTestnet = rpcClient.getStatus( ) isBlockchainSynced, r_time2 = rpcClient.isBlockchainSynced() except Exception as e: printException(getCallerName(), getFunctionName(), "exception updating RPC status:", str(e)) # clear status self.rpcClient = None self.sig_clearRPCstatus.emit() return rpcResponseTime = None if r_time1 is not None and r_time2 != 0: rpcResponseTime = round((r_time1 + r_time2) / 2, 3) # Do not update status if the user has selected a different server since the start of updateRPCStatus() if rpc_index != self.header.rpcClientsBox.currentIndex(): return with self.lock: self.rpcClient = rpcClient self.rpcConnected = status self.rpcLastBlock = lastBlock self.rpcStatusMess = statusMess self.isBlockchainSynced = isBlockchainSynced self.rpcResponseTime = rpcResponseTime # if testnet flag is changed, update api client and persist setting if isTestnet != self.isTestnetRPC: self.isTestnetRPC = isTestnet self.parent.cache['isTestnetRPC'] = persistCacheSetting( 'isTestnetRPC', isTestnet) self.apiClient = ApiClient(isTestnet) self.sig_RPCstatusUpdated.emit(rpc_index, fDebug)
def close(self): printDbg("DB: closing...") if not self.isOpen: err_msg = "Database already closed" printException(getCallerName(), "close()", err_msg, "") return with self.lock: try: if self.conn is not None: self.conn.close() self.conn = None self.isOpen = False printDbg("DB: Database closed") except Exception as e: err_msg = 'SQLite closing error' printException(getCallerName(), getFunctionName(), err_msg, e.args)
def startMN(self): if self.caller.hwStatus != 2: self.caller.myPopUp2(QMessageBox.Question, 'SPMT - hw device check', self.caller.hwStatusMess, QMessageBox.Ok) elif not self.caller.rpcConnected: self.caller.myPopUp2(QMessageBox.Question, 'SPMT - rpc device check', self.caller.rpcStatusMess, QMessageBox.Ok) else: try: self.masternodeToStart = self.mnToStartList.pop() printDbg("Starting...%s" % self.masternodeToStart.name) self.masternodeToStart.startMessage(self.caller.hwdevice, self.caller.rpcClient) # wait for signal when masternode.work is ready then ---> sendBroadcast except Exception as e: err_msg = "error in startMN" printException(getCallerName(), getFunctionName(), err_msg, e)
def addNewMasternode(self, mn): printDbg("DB: Adding new masternode") try: cursor = self.getCursor() cursor.execute("INSERT INTO MASTERNODES(name, ip, port, mnPrivKey," " hwAcc, isTestnet, isHardware, address, spath, pubkey, txid, txidn) " "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", (mn['name'], mn['ip'], mn['port'], mn['mnPrivKey'], mn['hwAcc'], mn['isTestnet'], 1 if mn['isHardware'] else 0, mn['collateral'].get('address'), mn['collateral'].get('spath'), mn['collateral'].get('pubKey'), mn['collateral'].get('txid'), mn['collateral'].get('txidn')) ) except Exception as e: err_msg = 'error writing new masternode to DB' printException(getCallerName(), getFunctionName(), err_msg, e.args) finally: self.releaseCursor()
def open(self): printDbg("DB: Opening...") if self.isOpen: raise Exception("Database already open") with self.lock: try: if self.conn is None: self.conn = sqlite3.connect(self.file_name) self.initTables() self.conn.commit() self.conn.close() self.conn = None self.isOpen = True printDbg("DB: Database open") except Exception as e: err_msg = 'SQLite initialization error' printException(getCallerName(), getFunctionName(), err_msg, e)
def getRewardsList(self, receiver=None): try: cursor = self.getCursor() if receiver is None: printDbg("DB: Getting rewards of all masternodes") cursor.execute("SELECT * FROM UTXOS") else: printDbg("DB: Getting rewards of %s" % receiver) cursor.execute("SELECT * FROM UTXOS WHERE receiver = ?", (receiver,)) rows = cursor.fetchall() except Exception as e: err_msg = 'error getting rewards list for %s' % receiver printException(getCallerName(), getFunctionName(), err_msg, e) rows = [] finally: self.releaseCursor() return self.rewards_from_rows(rows)
def onSave(self): if self.ui.signatureTextEdt.document().isEmpty(): mess = "Nothing to save. Sign message first." myPopUp_sb(self.main_wnd, QMessageBox.Warning, 'SPMT - no signature', mess) return options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getSaveFileName(self.main_wnd, "Save signature to file", "sig.txt", "All Files (*);; Text Files (*.txt)", options=options) try: if fileName: save_file = open(fileName, 'w', encoding="utf-8") save_file.write(self.ui.signatureTextEdt.toPlainText()) save_file.close() myPopUp_sb(self.main_wnd, QMessageBox.Information, 'SPMT - saved', "Signature saved to file") return except Exception as e: err_msg = "error writing signature to file" printException(getCallerName(), getFunctionName(), err_msg, e.args) myPopUp_sb(self.main_wnd, QMessageBox.Warning, 'SPMT - NOT saved', "Signature NOT saved to file")
def onSaveConsole(self): timestamp = strftime('%Y-%m-%d_%H-%M-%S', gmtime(now())) options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getSaveFileName( self, "Save Logs to file", "PET4L_Logs_%s.txt" % timestamp, "All Files (*);; Text Files (*.txt)", options=options) try: if fileName: printOK("Saving logs to %s" % fileName) log_file = open(fileName, 'w+') log_text = self.consoleArea.toPlainText() log_file.write(log_text) log_file.close() except Exception as e: err_msg = "error writing Log file" printException(getCallerName(), getFunctionName(), err_msg, e.args)
def loadTorrents_thread(self, ctrl): if not self.caller.rpcConnected: printException(getCallerName(), getFunctionName(), "RPC server not connected", "") return """ Preserved here for generations to come. Apparently returnPressed signal breaks if you set read-only while the connected function executes. self.ui.search_textbox.setReadOnly(True) """ self.torrents = self.caller.rpcClient.getTorrents() num_of_masternodes = self.caller.rpcClient.getMasternodeCount() if num_of_masternodes is None: printDbg( "Total number of masternodes not available. Background coloring not accurate" ) self.mnCount = 1 else: self.mnCount = num_of_masternodes.get("total")
def startMessage(self, device, rpcClient): # setup rpc connection self.rpcClient = rpcClient try: # update protocol version self.protocol_version = self.rpcClient.getProtocolVersion() # set current height self.currHeight = self.rpcClient.getBlockCount() except Exception as e: err_msg = "error in startMessage" printException(getCallerName(), getFunctionName(), err_msg, e) return # done signal from hwdevice thread try: device.sig1done.disconnect() except: pass device.sig1done.connect(self.finalizeStartMessage) # prepare sig1 (the one done on the hw device) self.signature1(device)
def process_ledger_exceptions_int(*args, **kwargs): try: return func(*args, **kwargs) except BTChipException as e: printDbg('Error while communicating with Ledger hardware wallet.') e.message = 'Error while communicating with Ledger hardware wallet.' if (e.sw in (0x6f01, 0x6d00, 0x6700, 0x6faa)): e.message = 'Make sure the PIVX app is open on your Ledger device.' e.message += '<br>If there is a program (such as Ledger Bitcoin Wallet) interfering with the USB communication, close it first.' elif (e.sw == 0x6982): e.message = 'Enter the PIN on your Ledger device.' printException(getCallerName(), getFunctionName(), e.message, e.args) raise DisconnectedException except Exception as e: e.message = str(e.args[0]) if str(e.args[0]) == 'read error': e.message = 'Read Error. Click "Connect" to reconnect HW device' printException(getCallerName(), getFunctionName(), e.message, e.args) raise DisconnectedException
def loadModules(): """Load all configured modules. Shutdown server if loading unsuccessful. Input: none Output: none """ global loadedModules global authModules global acctModules if not modulesConfig: return # try to import modules for moduleName, tokens in modulesConfig.items(): debug ('Loading module: ', moduleName) mod = BsdRadiusModule(moduleName) try: if (tokens['startup_module']): mod['startup_module'] = __import__(tokens['startup_module']) mod['startup_funct'] = loadFunction(mod['startup_module'], tokens['startup_function']) mod.startupCapable = True if (tokens['authorization_module']): mod['authz_module'] = __import__(tokens['authorization_module']) mod['authz_funct'] = loadFunction(mod['authz_module'], tokens['authorization_function']) mod.authorizationCapable = True if (tokens['authentication_module']): mod['authc_module'] = __import__(tokens['authentication_module']) mod['authc_funct'] = loadFunction(mod['authc_module'], tokens['authentication_function']) mod.authenticationCapable = True if (tokens['accounting_module']): mod['acct_module'] = __import__(tokens['accounting_module']) mod['acct_funct'] = loadFunction(mod['acct_module'], tokens['accounting_function']) mod.accountingCapable = True if (tokens['shutdown_module']): mod['shutdown_module'] = __import__(tokens['shutdown_module']) mod['shutdown_funct'] = loadFunction(mod['shutdown_module'], tokens['shutdown_function']) mod.shutdownCapable = True # catch all exceptions, report them to user and shutdown server except: misc.printException() misc.quit('Can not load BSD Radius server modules', 1) else: loadedModules[moduleName] = mod debug (mod) info ('Setting order of authorization modules') # set module executing order in authorization and accounting phases authModuleOrder = main_config['AUTHORIZATION']['modules'].split(',') for moduleName in authModuleOrder: moduleName = moduleName.strip() if moduleName not in loadedModules: misc.quit('Module "%s" not loaded' % moduleName, 1) # make list of authorization module references if not loadedModules[moduleName].authorizationCapable: misc.quit('Module "%s" not authorization capable' % moduleName, 1) authModules.append(loadedModules[moduleName]) info ('Setting order of accounting modules') acctModuleOrder = main_config['ACCOUNTING']['modules'].split(',') for moduleName in acctModuleOrder: moduleName = moduleName.strip() if moduleName not in loadedModules: misc.quit('Module "%s" not loaded' % moduleName, 1) if not loadedModules[moduleName].accountingCapable: misc.quit('Module "%s" not accounting capable' % moduleName, 1) acctModules.append(loadedModules[moduleName])