def __init__(self, dbPath): globs.log.write(1, 'Database.__init__({})'.format(dbPath)) # First, see if the database is there. If not, need to create it isThere = os.path.isfile(dbPath) if self.dbConn: globs.log.err( 'SQLite3 error: trying to reinitialize the database connection. Exiting program.' ) globs.closeEverythingAndExit( 1) # Abort program. Can't continue with DB error try: self.dbConn = sqlite3.connect(dbPath) except sqlite3.Error as err: globs.log.err( 'SQLite3 error connecting to {}: {}. Exiting program.'.format( dbPath, err.args[0])) globs.closeEverythingAndExit( 1) # Abort program. Can't continue with DB error if not isThere: self.dbInitialize() return None
def timeStampCrash(msg): globs.log.write(1, msg) globs.log.write( 1, 'This is likely caused by an email using a different date or time format than expected,\nparticularly if you\'re collecting emails from multiple locations or time zones.' ) globs.log.write( 1, 'Please check the \'dateformat=\' and \'timeformat=\' value(s) in the [main] section\nand any [<source>-<destination>] sections of your .rc file for accuracy.' ) globs.log.err( 'Date/time format specification mismatch. See log file for details. Exiting program.' ) globs.closeEverythingAndExit(1)
def execSqlStmt(self, stmt): globs.log.write(1, 'Database.execSqlStmt(): Executing SQL command.') globs.log.write(3, 'SQL stmt=[{}]'.format(stmt)) if not self.dbConn: return None curs = self.dbConn.cursor() try: curs.execute(stmt) except sqlite3.Error as err: globs.log.err('SQLite error: {}\n'.format(err.args[0])) globs.log.write(1, 'SQLite error: {}\n'.format(err.args[0])) globs.closeEverythingAndExit( 1) # Abort program. Can't continue with DB error return curs
def execSqlStmt(self, stmt): globs.log.write(globs.SEV_NOTICE, function='Database', action='execSqlStmt', msg='Executing SQL statement: [{}]'.format(stmt)) if not self.dbConn: return None # Set db cursor curs = self.dbConn.cursor() try: curs.execute(stmt) except sqlite3.Error as err: globs.log.write(globs.SEV_ERROR, function='Database', action='execSqlStmt', msg='SQLite error: {}'.format(err.args[0])) globs.closeEverythingAndExit(1) # Abort program. Can't continue with DB error # Return the cursor to the executed command result. return curs
def execReportInsertSql(self, sqlStmt, sqlData): globs.log.write(globs.SEV_NOTICE, function='Database', action='execReportInsertSql', msg='Inserting into emails table: sqlStmt=[{}] sqlData=[{}]'.format(sqlStmt, sqlData)) if not self.dbConn: return None # Set db cursor curs = self.dbConn.cursor() try: curs.execute(sqlStmt, sqlData) except sqlite3.Error as err: globs.log.write(globs.SEV_ERROR, function='Database', action='execReportInsertSql', msg='SQLite error: {}'.format(err.args[0])) globs.closeEverythingAndExit(1) # Abort program. Can't continue with DB error self.dbCommit() return None
def __init__(self, dbPath): globs.log.write(globs.SEV_NOTICE,function='Database', action='Init', msg='Initializing database manager.') # First, see if the database is there. If not, need to create it isThere = os.path.isfile(dbPath) if self.dbConn: # If not None then DB connection already exists. This is bad. globs.log.write(globs.SEV_ERROR, function='Database', action='Init', msg='SQLite3 Error: trying to reinitialize the database connection. Exiting program.') globs.closeEverythingAndExit(1) # Abort program. Can't continue with DB error try: self.dbConn = sqlite3.connect(dbPath) # Connect to database except sqlite3.Error as err: globs.log.write(globs.SEV_ERROR, function='Database', action='Init', msg='SQLite3 error connecting to database: {}. Exiting program.'.format(err.args[0])) globs.closeEverythingAndExit(1) # Abort program. Can't continue with DB error if not isThere: # Database did not exist. Need to initialize contents globs.log.write(globs.SEV_NOTICE, function='Database', action='Init', msg='New database. Needs initializing.') self.dbInitialize() return None
def execEmailInsertSql(self, emailParts): globs.log.write(globs.SEV_NOTICE, function='Database', action='execEmailInsertSql', msg='Inserting into emails table: messageId={} sourceComp={} destComp={}'.format(emailParts['header']['messageId'], emailParts['header']['sourceComp'], emailParts['header']['destComp'])) durVal = float(emailParts['body']['endTimestamp']) - float(emailParts['body']['beginTimestamp']) sqlStmt = "INSERT INTO emails(messageId, sourceComp, destComp, emailTimestamp, \ deletedFiles, deletedFolders, modifiedFiles, examinedFiles, \ openedFiles, addedFiles, sizeOfModifiedFiles, sizeOfAddedFiles, sizeOfExaminedFiles, \ sizeOfOpenedFiles, notProcessedFiles, addedFolders, tooLargeFiles, filesWithError, \ modifiedFolders, modifiedSymlinks, addedSymlinks, deletedSymlinks, partialBackup, \ dryRun, mainOperation, parsedResult, verboseOutput, verboseErrors, endTimestamp, \ beginTimestamp, duration, messages, warnings, errors, dbSeen, dupversion, logdata, bytesUploaded, bytesDownloaded) \ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?)" data = (emailParts['header']['messageId'], emailParts['header']['sourceComp'], emailParts['header']['destComp'], emailParts['header']['emailTimestamp'], emailParts['body']['deletedFiles'], \ emailParts['body']['deletedFolders'], emailParts['body']['modifiedFiles'], emailParts['body']['examinedFiles'], emailParts['body']['openedFiles'], \ emailParts['body']['addedFiles'], emailParts['body']['sizeOfModifiedFiles'], emailParts['body']['sizeOfAddedFiles'], emailParts['body']['sizeOfExaminedFiles'], emailParts['body']['sizeOfOpenedFiles'], \ emailParts['body']['notProcessedFiles'], emailParts['body']['addedFolders'], emailParts['body']['tooLargeFiles'], emailParts['body']['filesWithError'], \ emailParts['body']['modifiedFolders'], emailParts['body']['modifiedSymlinks'], emailParts['body']['addedSymlinks'], emailParts['body']['deletedSymlinks'], \ emailParts['body']['partialBackup'], emailParts['body']['dryRun'], emailParts['body']['mainOperation'], emailParts['body']['parsedResult'], emailParts['body']['verboseOutput'], \ emailParts['body']['verboseErrors'], emailParts['body']['endTimestamp'], emailParts['body']['beginTimestamp'], \ durVal, emailParts['body']['messages'], emailParts['body']['warnings'], emailParts['body']['errors'], emailParts['body']['dupversion'], emailParts['body']['logdata'], emailParts['body']['bytesUploaded'], emailParts['body']['bytesDownloaded']) globs.log.write(globs.SEV_DEBUG, function='Database', action='execEmailInsertSql', msg='sqlStmt=[{}]'.format(sqlStmt)) globs.log.write(globs.SEV_DEBUG, function='Database', action='execEmailInsertSql', msg='data=[{}]'.format(data)) if not self.dbConn: return None # Set db cursor curs = self.dbConn.cursor() try: curs.execute(sqlStmt, data) except sqlite3.Error as err: globs.log.write(globs.SEV_ERROR, function='Database', action='execEmailInsertSql', msg='SQLite error: {}'.format(err.args[0])) globs.closeEverythingAndExit(1) # Abort program. Can't continue with DB error self.dbCommit() return None
def __init__(self): globs.log.write(1,'Report:__init__()') self.reportOpts = {} # Dictionary of report options self.reportTits = {} # Dictionary of report titles titTmp = {} # Read name/value pairs from [report] section self.reportOpts = globs.optionManager.getRcSection('report') # Fix some of the data field types self.reportOpts['border'] = int(self.reportOpts['border']) # integer self.reportOpts['padding'] = int(self.reportOpts['padding']) # integer self.reportOpts['showsizedisplay'] = self.reportOpts['showsizedisplay'].lower() in ('true') # Convert to boolean self.reportOpts['displaymessages'] = self.reportOpts['displaymessages'].lower() in ('true') # Convert to boolean self.reportOpts['displaywarnings'] = self.reportOpts['displaywarnings'].lower() in ('true') # Convert to boolean self.reportOpts['displayerrors'] = self.reportOpts['displayerrors'].lower() in ('true') # Convert to boolean self.reportOpts['repeatheaders'] = self.reportOpts['repeatheaders'].lower() in ('true') # Convert to boolean self.reportOpts['nobackupwarn'] = int(self.reportOpts['nobackupwarn']) # integer # Basic field value checking # See if valid report name rptName = globs.progPath + '/rpt_' + self.reportOpts['style'] + '.py' validReport = os.path.isfile(rptName) if not validReport: globs.log.err('Invalid RC report style option in [report] section: style cannot be \'{}\''.format(self.reportOpts['style'])) globs.closeEverythingAndExit(1) if self.reportOpts['sortby'] not in ('source', 'destination', 'date', 'time'): globs.log.err('Invalid RC file sorting option in [report] section: sortby cannot be \'{}\''.format(self.reportOpts['sortby'])) globs.closeEverythingAndExit(1) if self.reportOpts['sizedisplay'].lower()[:4] not in ('byte', 'mega', 'giga'): globs.log.err('Invalid RC file size display option in [report] section: sizedisplay cannot be \'{}\''.format(self.reportOpts['sizedisplay'])) globs.closeEverythingAndExit(1) # Get list of existing headers in [headings] section titTmp = globs.optionManager.getRcSection('headings') if titTmp is not None: for name in titTmp: if titTmp[name] == '': # Empty string means column is not to be displayed rptColumns.remove(name) else: self.reportTits[name] = titTmp[name] # Remove these columns from the column list. We deal with these separately in the reports rptColumns.remove('jobmessages') rptColumns.remove('jobwarnings') rptColumns.remove('joberrors') globs.log.write(3, 'Report: reportOps=[{}]'.format(self.reportOpts)) globs.log.write(3, 'Report: reportTits=[{}]'.format(self.reportTits)) globs.log.write(3, 'Report: rptColumns=[{}]'.format(rptColumns)) return None
msg='Python version {}'.format(sys.version)) globs.log.write(globs.SEV_NOTICE, function='main', action='startup', msg='OS Platform: {}'.format(platform.platform())) globs.log.write(globs.SEV_NOTICE, function='main', action='startup', msg='Program path: {}'.format(globs.progPath)) # Check if we're running a compatible version of Python. Must be 3.0 or higher if sys.version_info.major < 3: globs.log.err( 'dupReport requires Python 3.0 or higher to run. Your installation is on version {}.{}.{}.\nPlease install a newer version of Python.' .format(sys.version_info.major, sys.version_info.minor, sys.version_info.micro)) globs.closeEverythingAndExit(1) # Start Program Timer startTime = time.time() # Initialize program options # This includes command line options and .rc file options canContinue = options.initOptions() if not canContinue: # Something changed in the .rc file that needs manual editing globs.closeEverythingAndExit(1) # Looking for version info on command line? (-V) if globs.opts['version']: # Print version info & exit versionInfo() globs.closeEverythingAndExit(0)
def __init__(self): globs.log.write(globs.SEV_NOTICE, function='Apprise', action='Init', msg='Initializing Apprise support') import apprise # Read name/value pairs from [apprise] section self.appriseOpts = globs.optionManager.getRcSection('apprise') if 'services' not in self.appriseOpts: globs.log.write( globs.SEV_ERROR, function='Apprise', action='Init', msg='Error: No services defined for Apprise notification') globs.closeEverythingAndExit(1) # Abort program. Can't continue # Set defaults for missing values self.appriseOpts[ 'title'] = 'Apprise Notification for #SRCDEST# Backup' if 'title' not in self.appriseOpts else self.appriseOpts[ 'title'] self.appriseOpts[ 'body'] = 'Completed at #COMPLETETIME#: #RESULT# - #ERRMSG#' if 'body' not in self.appriseOpts else self.appriseOpts[ 'body'] self.appriseOpts[ 'titletruncate'] = '0' if 'titletruncate' else self.appriseOpts[ 'titletruncate'] self.appriseOpts[ 'bodytruncate'] = '0' if 'bodytruncate' not in self.appriseOpts else self.appriseOpts[ 'bodytruncate'] self.appriseOpts[ 'msglevel'] = 'failure' if 'msglevel' not in self.appriseOpts else self.appriseOpts[ 'msglevel'] # Normalize .rc values self.appriseOpts['titletruncate'] = int( self.appriseOpts['titletruncate']) self.appriseOpts['bodytruncate'] = int( self.appriseOpts['bodytruncate']) self.appriseOpts['msglevel'] = self.appriseOpts['msglevel'].lower() # Check for correct message level indicator if self.appriseOpts['msglevel'] not in ('success', 'warning', 'failure'): globs.log.write(globs.SEV_ERROR, function='Apprise', action='Init', msg='Error: Bad apprise message level: {}'.format( self.appriseOpts['msglevel'])) globs.closeEverythingAndExit(1) # Abort program. Can't continue. # Initialize apprise library result = self.appriseConn = apprise.Apprise() globs.log.write( globs.SEV_NOTICE, function='Apprise', action='Init', msg='Initializing Apprise library. Result={}'.format(result)) # Add individual service URLs to connection self.services = self.appriseOpts['services'].split(",") for i in self.services: result = self.appriseConn.add(i) globs.log.write(globs.SEV_NOTICE, function='Apprise', action='Init', msg='Added service {}, result={}'.format( i, result)) globs.log.write(globs.SEV_NOTICE, function='Apprise', action='Init', msg='Apprise Initialization complete.') return None
def connect(self): globs.log.write(1, 'EmailServer.Connect({})'.format(self.dump())) globs.log.write( 3, 'server={} keepalive={}'.format(self.server, self.keepalive)) # See if a server connection is already established # This is the most common case, so check this first if self.server != None: if self.keepalive is False: # Do we care about keepalives? return None globs.log.write(3, 'Cheeking server connection') if self.protocol == 'imap': try: status = self.server.noop()[0] except: status = 'NO' if status != 'OK': globs.log.write( 1, 'Server {} timed out. Reconnecting.'.format( self.address)) self.server = None self.connect() elif self.protocol == 'pop3': try: status = self.server.noop() except: status = '+NO' if status != '+OK': globs.log.write( 1, 'Server {} timed out. Reconnecting.'.format( self.address)) self.server = None self.connect() elif self.protocol == 'smtp': try: status = self.server.noop()[0] except: # smtplib.SMTPServerDisconnected status = -1 if status != 250: # Disconnected. Need to reconnect to server globs.log.write( 1, 'Server {} timed out. Reconnecting.'.format( self.address)) self.server = None self.connect() else: # Need to establish server connection if self.protocol == 'imap': globs.log.write(1, 'Initial connect using IMAP') try: if self.encryption is not None: self.server = imaplib.IMAP4_SSL( self.address, self.port) else: self.server = imaplib.IMAP4(self.address, self.port) retVal, data = self.server.login(self.accountname, self.passwd) globs.log.write( 3, 'IMAP Logged in. retVal={} data={}'.format( retVal, data)) retVal, data = self.server.select(self.folder) globs.log.write( 3, 'IMAP Setting folder. retVal={} data={}'.format( retVal, data)) return retVal except imaplib.IMAP4.error: return None except imaplib.socket.gaierror: return None elif self.protocol == 'pop3': globs.log.write(1, 'Initial connect using POP3') try: if self.encryption is not None: self.server = poplib.POP3_SSL(self.address, self.port) else: self.server = poplib.POP3(self.address, self.port) retVal = self.server.user(self.accountname) globs.log.write(3, 'Logged in. retVal={}'.format(retVal)) retVal = self.server.pass_(self.passwd) globs.log.write( 3, 'Entered password. retVal={}'.format(retVal)) return retVal.decode() except Exception: return None elif self.protocol == 'smtp': globs.log.write(1, 'Initial connect using SMTP') try: self.server = smtplib.SMTP('{}:{}'.format( self.address, self.port)) if self.encryption is not None: # Do we need to use SSL/TLS? self.server.starttls() retVal, retMsg = self.server.login(self.accountname, self.passwd) globs.log.write( 3, 'Logged in. retVal={} retMsg={}'.format( retVal, retMsg)) return retMsg.decode() except (smtplib.SMTPAuthenticationError, smtplib.SMTPConnectError, smtplib.SMTPSenderRefused): return None else: # Bad protocol specification globs.log.err( 'Invalid protocol specification: {}. Aborting program.'. format(self.protocol)) globs.closeEverythingAndExit(1) return None return None