def queue_job(self, args, job_id=None):
        """
        Method to check sanity of job arguments and add
        job to redis queue
        """
        # Check for existing session info
        if job_id:
            if job_id.isalnum():
                if self.session_check(self.log_dir, job_id):
                    logger.debug('Valid session found')
                    started = rq.registry.StartedJobRegistry(queue=self.q)
                    cur_list = started.get_job_ids()
                    q_dict = self.crack_q.q_monitor(self.q)
                    if job_id in cur_list:
                        logger.error('Job is already running')
                        return jsonify({'msg': 'Job is already running'}), 500
                    if job_id in q_dict['Queued Jobs'].keys():
                        logger.error('Job is already queued')
                        return jsonify({'msg': 'Job is already queued'}), 500
                    outfile = str(valid.val_filepath(path_string=self.log_dir,
                                                     file_string='{}.cracked'.format(job_id)))
                    hash_file = str(valid.val_filepath(path_string=self.log_dir,
                                                       file_string='{}.hashes'.format(job_id)))
                    pot_path = str(valid.val_filepath(path_string=self.log_dir,
                                                      file_string='crackq.pot'))
                    job_deets = self.get_restore(self.log_dir, job_id)
                    job = self.q.fetch_job(job_id)  # lgtm
                    if not job_deets:
                        logger.debug('Job restor error. Never started')
                        return jsonify({'msg': 'Error restoring job'}), 500
                    elif not job_deets['restore']:
                        logger.debug('Job not previously started, restore = 0')
                        job_deets['restore'] = 0
                    elif job_deets['restore'] == 0:
                        logger.debug('Job not previously started, restore = 0')
                    wordlist = None
                    wordlist2 = None
                    rules = None
                    if 'wordlist' in job_deets:
                        if job_deets['wordlist'] in CRACK_CONF['wordlists']:
                            wordlist = CRACK_CONF['wordlists'][job_deets['wordlist']]
                    if 'wordlist2' in job_deets:
                        if job_deets['wordlist2']:
                            if job_deets['wordlist2'] in CRACK_CONF['wordlists']:
                                wordlist2 = CRACK_CONF['wordlists'][job_deets['wordlist2']]
                    if 'rules' in job_deets:
                        rules = check_rules(job_deets['rules'])
                        if rules is False:
                            return jsonify({'msg': 'Invalid rules selected'}), 500
                    mask_file = check_mask(job_deets['mask'])
                    # this is just set to use the first mask file in the list for now
                    mask = mask_file if mask_file else job_deets['mask']
                    try:
                        ###***make this (timeout - running time) for restored jobs??
                        timeout = job_deets['timeout']
                    except KeyError as err:
                        logger.warning('No timeout info in job details, using default')
                        timeout = 1814400
                    hc_args = {
                        'hash_file': hash_file,
                        'session': job_id,
                        'wordlist': wordlist,
                        'wordlist2': wordlist2,
                        'mask': mask,
                        'mask_file': True if mask_file else False,
                        'attack_mode': int(job_deets['attack_mode']),
                        'hash_mode': int(job_deets['hash_mode']),
                        'outfile': outfile,
                        'rules': rules,
                        'restore': job_deets['restore'],
                        'username': job_deets['username'] if 'user' in job_deets else None,
                        'increment': job_deets['increment'] if 'increment' in job_deets else None,
                        'increment_min': job_deets['increment_min'] if 'increment_min' in job_deets else None,
                        'increment_max': job_deets['increment_max'] if 'increment_max' in job_deets else None,
                        'brain': False if 'disable_brain' in job_deets else True,
                        'name': job_deets['name'] if 'name' in job_deets else None,
                        'pot_path': pot_path,
                        }
                    job = self.q.fetch_job(job_id)
                    job.meta['CrackQ State'] = 'Run/Restored'
                    job.save_meta()
                else:
                    return jsonify(ERR_INVAL_JID), 500
            else:
                return jsonify(ERR_INVAL_JID), 500
        else:
            logger.debug('Creating new session')
            job_id = uuid.uuid4().hex
            add_jobid(job_id)
            outfile = str(valid.val_filepath(path_string=self.log_dir,
                                             file_string='{}.cracked'.format(job_id)))
            hash_file = str(valid.val_filepath(path_string=self.log_dir,
                                               file_string='{}.hashes'.format(job_id)))
            pot_path = str(valid.val_filepath(path_string=self.log_dir,
                                              file_string='crackq.pot'))
            try:
                attack_mode = int(args['attack_mode'])
            except TypeError:
                attack_mode = None
            try:
                logger.debug('Writing hashes to file: {}'.format(hash_file))
                with open(hash_file, 'w') as hash_fh:
                    for hash_l in args['hash_list']:
                        hash_fh.write(hash_l.rstrip() + '\n')
            except KeyError as err:
                logger.debug('No hash list provided: {}'.format(err))
                return jsonify({'msg': 'No hashes provided'}), 500
            except IOError as err:
                logger.debug('Unable to write to hash file: {}'.format(err))
                return jsonify({'msg': 'System error'}), 500
            try:
                args['hash_mode']
                check_m = self.mode_check(args['hash_mode'])
            except KeyError:
                check_m = False
            logger.debug('Hash mode check: {}'.format(check_m))
            ###***change to if check_m
            if check_m is not False:
                try:
                    mode = int(check_m)
                except TypeError as err:
                    logger.error('Incorrect type supplied for hash_mode:'
                                 '\n{}'.format(err))
                    return jsonify({'msg': 'Invalid hash mode selected'}), 500
            else:
                return jsonify({'msg': 'Invalid hash mode selected'}), 500
            if attack_mode != 3:
                if args['wordlist'] in CRACK_CONF['wordlists']:
                    wordlist = CRACK_CONF['wordlists'][args['wordlist']]
                else:
                    return jsonify({'msg': 'Invalid wordlist selected'}), 500
            if attack_mode == 1:
                if 'wordlist2' in args:
                    if args['wordlist2'] in CRACK_CONF['wordlists']:
                        wordlist2 = CRACK_CONF['wordlists'][args['wordlist2']]
                    else:
                        return jsonify({'msg': 'Combinator mode requires 2 wordlists'}), 500
            else:
                wordlist2 = None
            try:
                mask_file = check_mask(args['mask_file'])
            except KeyError:
                mask_file = None
            try:
                mask = args['mask']
            except KeyError:
                mask = None
            ####***this is just set to use the first mask file in the list for now
            mask = mask_file[0] if mask_file else mask
            rules = check_rules(args['rules'])
            if rules is False:
                return {'msg': 'Invalid rules selected'}, 500
            try:
                username = args['username']
            except KeyError as err:
                logger.debug('Username value not provided')
                username = False
            try:
                increment = args['increment']
            except KeyError as err:
                logger.debug('Increment value not provided')
                increment = False
            try:
                increment_min = args['increment_min']
            except KeyError as err:
                logger.debug('Increment min value not provided')
                increment_min = None
            try:
                increment_max = args['increment_max']
            except KeyError as err:
                logger.debug('Increment max value not provided')
                increment_max = None
            try:
                if args['disable_brain']:
                    logger.debug('Brain disabled')
                    brain = False
                else:
                    brain = True
            except KeyError as err:
                logger.debug('Brain not disabled: {}'.format(err))
                brain = True
            try:
                name = args['name']
            except KeyError as err:
                logger.debug('Name value not provided')
                name = None
            try:
                potcheck = args['potcheck']
            except KeyError as err:
                logger.debug('Potcheck value not provided')
                potcheck = False
            timeout = 1814400
            if 'jobtimeout' in CRACK_CONF:
                if not CRACK_CONF['jobtimeout']['Modify']:
                    logger.debug('Timeout modification not permitted')
                    timeout = CRACK_CONF['jobtimeout']['Value']
                else:
                    if 'timeout' in args:
                        timeout = args['timeout']
            hc_args = {
                'hash_file': hash_file,
                'session': job_id,
                'wordlist': wordlist if attack_mode != 3 else None,
                'wordlist2': wordlist2 if attack_mode == 1 else None,
                'mask': mask if attack_mode > 2 else None,
                'mask_file': True if mask_file else False,
                'attack_mode': attack_mode,
                'hash_mode': mode,
                'outfile': outfile,
                'rules': rules,
                'username': username,
                'increment': increment,
                'increment_min': increment_min,
                'increment_max': increment_max,
                'brain': brain,
                'name': name,
                'pot_path': pot_path,
                'restore': 0,
                'potcheck': potcheck
            }
        q_args = {
            'job_id': job_id,
            'kwargs': hc_args,
            }
        try:
            q = self.crack_q.q_connect()
            try:
                if hc_args['restore'] > 0:
                    job = self.q.fetch_job(job_id)
                    if job.meta['brain_check']:
                        logger.debug('Brain check previously complete')
                    elif job.meta['brain_check'] is None:
                        self.speed_check(q_args=q_args)
                        time.sleep(3)
                    else:
                        logger.debug('Restored job, disabling speed check')
                else:
                    logger.debug('Job not a restore, queuing speed_check')
                    self.speed_check(q_args=q_args)
                    time.sleep(3)
            ###***remove below now?
            except KeyError as err:
                logger.debug('Job not a restore, queuing speed_check')
                self.speed_check(q_args=q_args)
                time.sleep(3)
            self.crack_q.q_add(q, q_args, timeout=timeout)
            logger.debug('API Job {} added to queue'.format(job_id))
            logger.debug('Job Details: {}'.format(q_args))
            job = self.q.fetch_job(job_id)
            if 'task_id' in args:
                job.meta['task_id'] = args['task_id']
            job.meta['email_count'] = 0
            if 'notify' in args:
                job.meta['notify'] = args['notify']
            else:
                job.meta['notify'] = False
            if current_user.email:
                if email_check(current_user.email):
                    job.meta['email'] = str(current_user.email)
                    job.meta['last_seen'] = str(current_user.last_seen)
                elif email_check(current_user.username):
                    job.meta['email'] = current_user.username
                    job.meta['last_seen'] = str(current_user.last_seen)
            job.meta['CrackQ State'] = 'Run/Restored'
            job.meta['Speed Array'] = []
            job.save_meta()
            return job_id, 202
        except KeyError as err:
            logger.warning('Key missing from meta data:\n{}'.format(err))
            return job_id, 202
        except TypeError as err:
            logger.warning('Type error in job meta data:\n{}'.format(err))
            return job_id, 202

        Method to check sanity of job arguments and add
        job to redis queue
        
crackq/cq_api.py