diff --git a/COMPILER.bat b/make.bat
similarity index 56%
rename from COMPILER.bat
rename to make.bat
index b69c8cf..5b0e6e6 100644
--- a/COMPILER.bat
+++ b/make.bat
@@ -1,10 +1,9 @@
@echo off
-set /p version=Numero de version:
+title Compilation de CNIRevelator
+call pyinstaller -w -D --exclude-module PyQt5 --bootloader-ignore-signals --add-data "C:\users\adrie\Anaconda3\Lib\site-packages\tld\res\effective_tld_names.dat.txt";"tld\res" --add-data "id-card.ico";"id-card.ico" -i "id-card.ico" -n CNIRevelator src\analyzer\CNI_Revelator.py
-title Compilation du programme final
-
-call pyinstaller -w -D --exclude-module PyQt5 --bootloader-ignore-signals --add-data "C:\users\adrie\Anaconda3\Lib\site-packages\tld\res\effective_tld_names.dat.txt";"tld\res" --add-data "id-card.ico";"id-card.ico" -i "id-card.ico" -n CNIRevelator_%version%.exe CNI_Revelator.py
+copy LICENSE dist\CNIRevelator\
pause
diff --git a/CNI_GLOBALVAR.py b/src/analyzer/CNI_GLOBALVAR.py
similarity index 51%
rename from CNI_GLOBALVAR.py
rename to src/analyzer/CNI_GLOBALVAR.py
index db74c3e..ba94884 100644
--- a/CNI_GLOBALVAR.py
+++ b/src/analyzer/CNI_GLOBALVAR.py
@@ -1,47 +1,59 @@
-"""
-********************************************************************************
- *** Projet CNI_Revelator ***
-
- GNU GPL * 07/2018
-
- Adrien Bourmault
-
- VARIABLES
-
-********************************************************************************
-"""
-
-class changelog:
-
- def __init__(self):
- self.isOn = False
- self.text = "Mise-à-jour de sécurité avec corrections suivantes :\n- ajout de la signature numérique de l'exécutable\n- ajout d'une clé de cryptage plus performante pour le stockage des identifiants\n- passage à la méthode de cryptage AES256\n\nAjout/correction des fonctionnalités suivantes :\n- somme de contrôle des téléchargements pour une meilleure fiabilité\n- amélioration de présentation du log en cas d'erreur\n- correction d'un bug affectant l'analyse des MRZ après la correction manuelle\n\nEt un petit bonjour à tout le monde! ;)"
-
-
-CST_REV = '0'
-CST_VERTITLE = '2.2'
-CST_TAB_VER = ['2', '2', '5']
-CST_VER = '{0}.{1}.{2}'.format(CST_TAB_VER[0], CST_TAB_VER[1], CST_TAB_VER[2])
-CST_TYPE = 'Final Release'
-CST_NAME = 'CNIRevelator'
-CST_TITLE = CST_NAME + ' ' + CST_VER + ' - GNU/GPL Licensing 2018'
-CST_MARK = CST_NAME + ' ' + CST_TYPE + ' ' + CST_VER + ' - by NeoX, GNU/GPL Licensing 2018'
-CST_SUM_VER = int(CST_TAB_VER[0]) * 100 + int(CST_TAB_VER[1]) * 10 + int(CST_TAB_VER[2])
-CST_LINK = 'http://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/'
-CST_COLOR = '#003380'
-CST_TesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
-
-
-import base64, hashlib
-from Crypto import Random
-from Crypto.Cipher import AES
-from tkinter import *
-from tkinter.messagebox import *
-from tkinter import filedialog
-from tkinter import ttk
-import os, time, threading, sys, urllib.request as urllib2, urllib.error as URLExcept, random
-from datetime import datetime
-
-CST_FOLDER = os.getenv('APPDATA') + '/CNIRevelator/'
-CST_CRYPTOKEY = '82Xh!efX3#@P~2eG'
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application launcher & updater *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
+
+class changelog:
+
+ def __init__(self):
+ self.isOn = False
+ self.text = "Mise-à-jour de sécurité avec corrections suivantes :\n- ajout de la signature numérique de l'exécutable\n- ajout d'une clé de cryptage plus performante pour le stockage des identifiants\n- passage à la méthode de cryptage AES256\n\nAjout/correction des fonctionnalités suivantes :\n- somme de contrôle des téléchargements pour une meilleure fiabilité\n- amélioration de présentation du log en cas d'erreur\n- correction d'un bug affectant l'analyse des MRZ après la correction manuelle\n\nEt un petit bonjour à tout le monde! ;)"
+
+
+CST_REV = '0'
+CST_VERTITLE = '2.2'
+CST_TAB_VER = ['2', '2', '5']
+CST_VER = '{0}.{1}.{2}'.format(CST_TAB_VER[0], CST_TAB_VER[1], CST_TAB_VER[2])
+CST_TYPE = 'Final Release'
+CST_NAME = 'CNIRevelator'
+CST_TITLE = CST_NAME + ' ' + CST_VER + ' - GNU/GPL Licensing 2018'
+CST_MARK = CST_NAME + ' ' + CST_TYPE + ' ' + CST_VER + ' - by NeoX, GNU/GPL Licensing 2018'
+CST_SUM_VER = int(CST_TAB_VER[0]) * 100 + int(CST_TAB_VER[1]) * 10 + int(CST_TAB_VER[2])
+CST_LINK = 'http://neoxgroup.eu/ftpaccess/Applicatifs/CNIRevelator/'
+CST_COLOR = '#003380'
+CST_TesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
+
+
+import base64, hashlib
+from Crypto import Random
+from Crypto.Cipher import AES
+from tkinter import *
+from tkinter.messagebox import *
+from tkinter import filedialog
+from tkinter import ttk
+import os, time, threading, sys, urllib.request as urllib2, urllib.error as URLExcept, random
+from datetime import datetime
+
+CST_FOLDER = os.getenv('APPDATA') + '/CNIRevelator/'
+CST_CRYPTOKEY = '82Xh!efX3#@P~2eG'
CST_CHANGELOG = changelog()
\ No newline at end of file
diff --git a/CNI_Revelator.py b/src/analyzer/CNI_Revelator.py
similarity index 66%
rename from CNI_Revelator.py
rename to src/analyzer/CNI_Revelator.py
index dd890b1..947d93f 100644
--- a/CNI_Revelator.py
+++ b/src/analyzer/CNI_Revelator.py
@@ -1,107 +1,120 @@
-"""
-********************************************************************************
- *** Projet CNI_Revelator ***
-
- GNU GPL * 07/2018
-
- Adrien Bourmault
-
- main
-
-********************************************************************************
-"""
-from CNI_GLOBALVAR import *
-try:
- os.remove('error.log')
- os.remove('conf.ig')
-except:
- print("pass log deletion")
- pass
-
-if not os.path.exists(CST_FOLDER):
- try:
- os.makedirs(CST_FOLDER)
- except IOError:
- print("pass IO ERROR")
- pass
-
-print("debug")
-import logging
-from logging import FileHandler
-logger = logging.getLogger()
-logger.setLevel(logging.INFO)
-formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
-error_handler = FileHandler((CST_FOLDER + '\\error.log'), mode='w', encoding='utf-8', delay=True)
-info_handler = FileHandler((CST_FOLDER + '\\cnirevelator.log'), mode='w', encoding='utf-8')
-error_handler.setLevel(logging.ERROR)
-logger.addHandler(error_handler)
-info_handler.setLevel(logging.DEBUG)
-info_handler.setFormatter(formatter)
-logger.addHandler(info_handler)
-from CNI_classes import *
-from CNI_Update import *
-
-def main(logger):
- logger.error('')
- logger.info('main() : **** Creating App_main() ****')
- main_w = App_main(logger)
- main_w.montext('* ' + CST_NAME + ' ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + ' *\n')
- import CNI_pytesseract as pytesseract
- try:
- os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
- os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
- tesser_version = pytesseract.get_tesseract_version()
- except Exception as e:
- logger.error('main() : **** ERROR WITH TESSERACT MODULE ' + str(e) + ' ****')
- else:
- text = 'Tesseract version ' + str(tesser_version) + ' Licensed Apache 2004 successfully initiated\n'
- main_w.montext(text)
- main_w.montext('\n\nEntrez la première ligne de MRZ svp \n')
- if CST_CHANGELOG.isOn:
- showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + '\n\n' + CST_CHANGELOG.text), parent=main_w)
- logger.info('main() : **** Launching App_main() ****')
- main_w.mainloop()
- logger.info('main() : **** Ending App_main() ****')
-
-
-logger.info('launcher : ' + CST_NAME + ' ' + CST_VER)
-logger.info('launcher : *****Hello World*****')
-logger.info('launcher : *****Launching SoftUpdate()*****')
-try:
- Answer = SoftUpdate(logger)
-except Exception as e:
- logger.info('launcher : *****FATAL ERROR*****' + str(e))
- os.abort()
-
-logger.info('launcher : *****Ending SoftUpdate()*****')
-try:
- if Answer == True:
- logger.info('launcher : *****Launching main()*****')
- State = main(logger)
-except Exception as e:
- logger.info('launcher : *****FATAL ERROR*****' + str(e))
- os.abort()
-
-logger.info('launcher : *****Ending main()*****')
-logger.info('launcher : *****Goodbye!*****')
-handlers = logger.handlers[:]
-for handler in handlers:
- handler.close()
- logger.removeHandler(handler)
-
-try:
- with open(CST_FOLDER + '\\error.log') as (echo):
- try:
- os.remove('error.log')
- except OSError:
- pass
-
- from shutil import copyfile
- temptwo = str(echo.read())
- if len(temptwo) != 1:
- copyfile(CST_FOLDER + '\\cnirevelator.log', 'error.log')
-except IOError:
- pass
-
-print("exit")
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application launcher & updater *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
+
+from CNI_GLOBALVAR import *
+try:
+ os.remove('error.log')
+ os.remove('conf.ig')
+except:
+ print("pass log deletion")
+ pass
+
+if not os.path.exists(CST_FOLDER):
+ try:
+ os.makedirs(CST_FOLDER)
+ except IOError:
+ print("pass IO ERROR")
+ pass
+
+print("debug")
+import logging
+from logging import FileHandler
+logger = logging.getLogger()
+logger.setLevel(logging.INFO)
+formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
+error_handler = FileHandler((CST_FOLDER + '\\error.log'), mode='w', encoding='utf-8', delay=True)
+info_handler = FileHandler((CST_FOLDER + '\\cnirevelator.log'), mode='w', encoding='utf-8')
+error_handler.setLevel(logging.ERROR)
+logger.addHandler(error_handler)
+info_handler.setLevel(logging.DEBUG)
+info_handler.setFormatter(formatter)
+logger.addHandler(info_handler)
+from CNI_classes import *
+from CNI_Update import *
+
+def main(logger):
+ logger.error('')
+ logger.info('main() : **** Creating App_main() ****')
+ main_w = App_main(logger)
+ main_w.montext('* ' + CST_NAME + ' ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + ' *\n')
+ import CNI_pytesseract as pytesseract
+ try:
+ os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
+ os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
+ tesser_version = pytesseract.get_tesseract_version()
+ except Exception as e:
+ logger.error('main() : **** ERROR WITH TESSERACT MODULE ' + str(e) + ' ****')
+ else:
+ text = 'Tesseract version ' + str(tesser_version) + ' Licensed Apache 2004 successfully initiated\n'
+ main_w.montext(text)
+ main_w.montext('\n\nEntrez la première ligne de MRZ svp \n')
+ if CST_CHANGELOG.isOn:
+ showinfo('Changelog : résumé de mise à jour', ('Version du logiciel : ' + CST_VER + ' ' + CST_TYPE + ' Revision ' + CST_REV + '\n\n' + CST_CHANGELOG.text), parent=main_w)
+ logger.info('main() : **** Launching App_main() ****')
+ main_w.mainloop()
+ logger.info('main() : **** Ending App_main() ****')
+
+
+logger.info('launcher : ' + CST_NAME + ' ' + CST_VER)
+logger.info('launcher : *****Hello World*****')
+logger.info('launcher : *****Launching SoftUpdate()*****')
+try:
+ Answer = SoftUpdate(logger)
+except Exception as e:
+ logger.info('launcher : *****FATAL ERROR*****' + str(e))
+ os.abort()
+
+logger.info('launcher : *****Ending SoftUpdate()*****')
+try:
+ if Answer == True:
+ logger.info('launcher : *****Launching main()*****')
+ State = main(logger)
+except Exception as e:
+ logger.info('launcher : *****FATAL ERROR*****' + str(e))
+ os.abort()
+
+logger.info('launcher : *****Ending main()*****')
+logger.info('launcher : *****Goodbye!*****')
+handlers = logger.handlers[:]
+for handler in handlers:
+ handler.close()
+ logger.removeHandler(handler)
+
+try:
+ with open(CST_FOLDER + '\\error.log') as (echo):
+ try:
+ os.remove('error.log')
+ except OSError:
+ pass
+
+ from shutil import copyfile
+ temptwo = str(echo.read())
+ if len(temptwo) != 1:
+ copyfile(CST_FOLDER + '\\cnirevelator.log', 'error.log')
+except IOError:
+ pass
+
+print("exit")
sys.exit(0)
\ No newline at end of file
diff --git a/CNI_Update.py b/src/analyzer/CNI_Update.py
similarity index 94%
rename from CNI_Update.py
rename to src/analyzer/CNI_Update.py
index 9710c8e..834dd39 100644
--- a/CNI_Update.py
+++ b/src/analyzer/CNI_Update.py
@@ -1,493 +1,506 @@
-"""
-********************************************************************************
- *** Projet CNI_Revelator ***
-
- GNU GPL * 07/2018
-
- Adrien Bourmault
-
- UPDATE
-
-********************************************************************************
-"""
-from CNI_GLOBALVAR import *
-from CNI_classes import *
-import hashlib
-from pypac import PACSession
-from requests.auth import HTTPProxyAuth
-import subprocess
-
-def SoftUpdate(logger):
- global ret
- global upwin
- import zipfile
- for f in os.listdir(CST_FOLDER):
- if f[-4:] == '.tif':
- try:
- os.remove(CST_FOLDER + '\\' + f)
- except PermissionError as e:
- logger.info('SoftUpdate() : Failing to purge : ' + str(e))
-
- logger.info('SoftUpdate() : Looking for older version in dir...')
- list = os.listdir('.')
- for file in list:
- if file.startswith('CNIRevelator_'):
- temp = ['0', '0', '0']
- ver = file[13:].split('.')
- for i in range(len(ver)):
- if ver[i] != 'exe':
- try:
- temp[i] = ver[i]
- except:
- pass
-
- ver = temp.copy()
- try:
- sum_ver = int(ver[0]) * 100 + int(ver[1]) * 10 + int(ver[2])
- if sum_ver < CST_SUM_VER:
- if file[-3:] == 'exe':
- os.remove(file)
- logger.info('SoftUpdate() : Removed old version : ' + str(file))
- CST_CHANGELOG.isOn = True
- except Exception as e:
- logger.error('SoftUpdate() : Failing to remove old version ' + str(file) + ' : ' + str(e))
-
- def updating():
-
- def updator():
- global ret
- logger.info('[updator() thread] : Welcome !')
- ret = 11
- canvas.itemconfigure(message, text='Recherche de mises-à-jour...')
- p.configure(mode='indeterminate', value=0, maximum=20)
- p.start()
- upwin.update()
- logger.info('[updator() thread] : Looking for updates...')
- try:
-
- def download(url, filename):
- global key
- global login
- try:
- logger.info('[download() thread] : Trying getting credentials in the config file')
- with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
- AESObj = AESCipher(CST_CRYPTOKEY)
- try:
- tempone = AESObj.decrypt(config.read())
- if tempone != '||':
- if tempone.find('||') != -1:
- IPN, IPN_PASS = tempone.split('||')[0:2]
- else:
- raise ValueError('Cryptokey is bad !')
- else:
- IPN = ''
- IPN_PASS = ''
- except Exception as e:
- raise IOError(str(e))
- else:
- logger.info('[download() thread] : Got credentials !')
- session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
- logger.info('[download() thread] : Authenticated to proxy successfully')
- except IOError as e:
- logger.error('[download() thread] : False or absent credentials in the config file : ' + str(e))
- NoConnect = True
- while NoConnect:
-
- class LoginDialog(Toplevel):
-
- def __init__(self, parent):
- super().__init__(parent)
- self.title('Connexion')
- Label(self, text='IPN : ').pack()
- self.entry_login = Entry(self)
- self.entry_login.insert(0, '')
- self.entry_login.pack()
- Label(self, text='Mot de passe : ').pack()
- self.entry_pass = Entry(self, show='*')
- self.entry_pass.insert(0, '')
- self.entry_pass.pack()
- Button(self, text='Connexion', command=(self.connecti)).pack()
- self.resizable(width=False, height=False)
- w = 150
- h = 110
- self.update()
- ws = self.winfo_screenwidth()
- hs = self.winfo_screenheight()
- if getattr(sys, 'frozen', False):
- self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
- else:
- self.iconbitmap('id-card.ico')
- upwin.update()
- x = ws / 2 - w / 2
- y = hs / 2 - h / 2
- self.geometry('%dx%d+%d+%d' % (w, h, x, y))
-
- def connecti(self):
- global key
- global login
- login = self.entry_login.get().strip()
- key = self.entry_pass.get().strip()
- self.destroy()
-
- session = PACSession()
- if session.get_pac() == None:
- IPN = ''
- IPN_PASS = ''
- NoConnect = False
- break
- canvas.itemconfigure(message, text='En attente de connexion au serveur proxy...')
- login = ''
- key = ''
- result = LoginDialog(upwin)
- result.transient(upwin)
- result.grab_set()
- upwin.wait_window(result)
- IPN = login
- IPN_PASS = key
- session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
- Ans = session.get('http://www.google.com')
- if str(Ans) == '':
- canvas.itemconfigure(message, text='Identifiants erronés, accès refusé')
- logger.info('[download() thread] : 407 Error')
- time.sleep(1)
- else:
- if str(Ans) == '':
- logger.info('[download() thread] : Connection ok !')
- NoConnect = False
- else:
- raise IOError()
-
- AESObj = AESCipher(CST_CRYPTOKEY)
- with open(CST_FOLDER + 'conf.ig', 'wb+') as (f):
- logger.info('[download() thread] : Saving credentials in encrypted config file')
- f.write(AESObj.encrypt(IPN + '||' + IPN_PASS))
-
- if IPN == 'i005316':
- canvas.itemconfigure(message, text='Bienvenue Thierry !')
- else:
- if IPN == 'i020251':
- canvas.itemconfigure(message, text='Bienvenue Samia !')
- else:
- if IPN == 'i018410':
- canvas.itemconfigure(message, text='Bienvenue Adrien !')
- else:
- if IPN == 'i003067':
- canvas.itemconfigure(message, text='Bienvenue Remy !')
- else:
- if IPN == 'i018422':
- canvas.itemconfigure(message, text='Bienvenue Eloise !')
- time.sleep(1)
- try:
- Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
- PROXY_USABLE = Prox_us[6:-1].split(';')[0]
- proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
- ph = urllib2.ProxyHandler({'http': proxy_server_url})
- auth = urllib2.ProxyBasicAuthHandler()
- server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
- urllib2.install_opener(server)
- logger.info('[download() thread] : Proxy connection initiated successfully')
- except:
- logger.info('[download() thread] : Proxy connection not initiated')
-
- try:
- urllib2.urlretrieve(url, filename)
- return True
- except Exception as e:
- logger.error('[download() thread] : HTTP ERROR ')
- return e
-
- logger.info('[updator() thread] : Prepare downloading the version recap file...')
- tempfile = CST_FOLDER + 'temp' + str(random.randint(11111, 99999)) + '.cniu'
- isOk = download(CST_LINK + 'cnir.ver', tempfile)
- if not isOk:
- raise isOk
- urllib2.urlcleanup()
- logger.info('[updator() thread] : Opening version recap file...')
- file_ver = open(tempfile, 'r')
- logger.info('[updator() thread] : Reading version recap file...')
- version = file_ver.read()
- logger.info('[updator() thread] : Closing version recap file...')
- repert = version.split('|')
- file_ver.close()
- logger.info('[updator() thread] : Deleting version recap file...')
- os.remove(tempfile)
- logger.info('[updator() thread] : Parsing informations about version...')
- final_f = 'CNI_file'
- final_ver = ['0', '0', '0']
- final_hash = ''
- for sentence in repert:
- try:
- file, hashref = sentence.split(':')
- except ValueError:
- pass
- else:
- if str.startswith(file, CST_NAME):
- ver = file.replace(CST_NAME + '_', '').split('.')
- temp = [
- '0', '0', '0']
- for i in range(len(ver)):
- temp[i] = ver[i]
-
- ver = temp.copy()
- sum_fver = int(final_ver[0]) * 100 + int(final_ver[1]) * 10 + int(final_ver[2])
- sum_ver = int(ver[0]) * 100 + int(ver[1]) * 10 + int(ver[2])
- if sum_ver > sum_fver:
- final_ver = ver.copy()
- final_f = file
- final_hash = hashref
-
- sum_ver = int(final_ver[0]) * 100 + int(final_ver[1]) * 10 + int(final_ver[2])
- if final_f != 'CNI_file':
- if sum_ver > CST_SUM_VER:
- logger.info('[updator() thread] : New version of CNIRevelator found !')
- canvas.itemconfigure(message, text='Mise à jour disponible ! Préparation du téléchargement...')
- logger.info('[updator() thread] : Preparing download')
- with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
- logger.info('[updator() thread] : Reading credentials for proxy in config file...')
- AESObj = AESCipher(CST_CRYPTOKEY)
- IPN, IPN_PASS = AESObj.decrypt(config.read()).split('||')[0:2]
- session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
- try:
- Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
- PROXY_USABLE = Prox_us[6:-1].split(';')[0]
- proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
- ph = urllib2.ProxyHandler({'http': proxy_server_url})
- auth = urllib2.ProxyBasicAuthHandler()
- server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
- logger.info('[updator() thread] : Connection to the proxy initiated successfully !')
- except:
- canvas.itemconfigure(message, text='Téléchargement en connexion directe...')
- server = urllib2.build_opener()
- logger.info('[updator() thread] : Direct connection initiated successfully')
-
- logger.info('[updator() thread] : Launching download of ' + final_f)
- Statut = Download(CST_LINK + final_f, final_f, final_f, server, p, canvas, message, logger)
- BLOCKSIZE = 65536
- hasher = hashlib.sha1()
- try:
- with open(final_f, 'rb') as (afile):
- buf = afile.read(BLOCKSIZE)
- while len(buf) > 0:
- hasher.update(buf)
- buf = afile.read(BLOCKSIZE)
-
- hashcod = hasher.hexdigest()
- if hashcod != final_hash:
- Statut.success = False
- logger.error('[updator() thread] : Hashcode Error :' + final_f)
- try:
- os.remove(final_f)
- except IOError:
- pass
-
- else:
- logger.info('[updator() thread] : Hashcode pass :' + final_f)
- except FileNotFoundError as e:
- logger.error('[updator() thread] : File not found ' + final_f)
-
- if Statut.success:
- try:
- os.rename(final_f, final_f + '.exe')
- except IOError:
- logger.error('[updator() thread] : Unable to rename the file ! Wait 3 sec and retry')
- time.sleep(3)
- try:
- os.rename(final_f, final_f + '.exe')
- except IOError:
- logger.critical('[updator() thread] : Unable to rename the file !')
-
- else:
- canvas.itemconfigure(message, text='Téléchargement terminé ! Préparation du lancement...')
- logger.info('[updator() thread] : Download of ' + final_f + 'finished successfully')
- p.configure(mode='indeterminate', value=0, maximum=20)
- p.start()
- time.sleep(1)
- logger.info('[updator() thread] : Launching ' + final_f)
- try:
- proc = subprocess.Popen((final_f + '.exe'), shell=False, stdin=None, stdout=None, stderr=None, close_fds=True)
- except:
- logger.error('[updator() thread] : Unable to start the new version ! Wait 3 sec and retry')
- time.sleep(3)
- try:
- proc = subprocess.Popen((final_f + '.exe'), shell=False, stdin=None, stdout=None, stderr=None, close_fds=True)
- except Exception as e:
- logger.critical('[updator() thread] : Unable to start the new version ! Stopping : ' + str(e))
- showerror("Erreur d'appel de procédure distante", 'Le lancement du nouveau programme a échoué, vous devez le lancer manuellement une fois cette fenêtre fermée', parent=upwin)
-
- ret = 12
- else:
- canvas.itemconfigure(message, text='Echec de la mise à jour : Erreur HTTP. Préparation du lancement...')
- logger.error('[updator() thread] : Update has failed with HTTP error')
- time.sleep(1)
- canvas.itemconfigure(message, text='Logiciel déjà à jour. Préparation du lancement...')
- logger.info('[updator() thread] : CNIRevelator is up to date !')
- time.sleep(1)
- ret = 11
- if os.path.exists(CST_FOLDER + 'Tesseract-OCR4\\tesseract.exe'):
- os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
- os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
- else:
- final_f = 'tesseract_4'
- logger.info('[updator() thread] : Downloading tesseract 4 !')
- canvas.itemconfigure(message, text='Mise à jour du module OCR ! Préparation du téléchargement...')
- logger.info('[updator() thread] : Preparing download')
- with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
- logger.info('[updator() thread] : Reading credentials for proxy in config file...')
- AESObj = AESCipher(CST_CRYPTOKEY)
- IPN, IPN_PASS = AESObj.decrypt(config.read()).split('||')[0:2]
- session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
- try:
- Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
- PROXY_USABLE = Prox_us[6:-1].split(';')[0]
- proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
- ph = urllib2.ProxyHandler({'http': proxy_server_url})
- auth = urllib2.ProxyBasicAuthHandler()
- server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
- logger.info('[updator() thread] : Connection to the proxy initiated successfully !')
- except:
- canvas.itemconfigure(message, text='Téléchargement en connexion directe...')
- server = urllib2.build_opener()
- logger.info('[updator() thread] : Direct connection initiated successfully')
-
- logger.info('[updator() thread] : Launching download of ' + final_f)
- Statut = Download(CST_LINK + final_f, CST_FOLDER + final_f, final_f, server, p, canvas, message, logger)
- hashcod = ''
- logger.info('[updator() thread] : Verifying hashcode of ' + final_f)
- BLOCKSIZE = 65536
- hasher = hashlib.sha1()
- try:
- with open(CST_FOLDER + final_f, 'rb') as (afile):
- buf = afile.read(BLOCKSIZE)
- while len(buf) > 0:
- hasher.update(buf)
- buf = afile.read(BLOCKSIZE)
-
- hashcod = hasher.hexdigest()
- if hashcod != CST_TesserHash:
- Statut.success = False
- logger.error('[updator() thread] : Hashcode Error : ' + final_f)
- try:
- os.remove(CST_FOLDER + final_f)
- except IOError:
- pass
-
- else:
- logger.info('[updator() thread] : Hashcode pass : ' + final_f)
- except FileNotFoundError as e:
- logger.error('[updator() thread] : File not found ' + final_f)
-
- if Statut.success:
- canvas.itemconfigure(message, text='Téléchargement terminé ! Installation...')
- logger.info('[updator() thread] : Download of ' + final_f + 'finished successfully')
- p.configure(mode='indeterminate', value=0, maximum=20)
- p.start()
- try:
- zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
- zip_ref.extractall(CST_FOLDER)
- zip_ref.close()
- os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
- os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
- canvas.itemconfigure(message, text='Installation terminée !')
- except:
- logger.error('[updator() thread] : Unable to install the module. Wait and retry')
- time.sleep(3)
- try:
- zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
- zip_ref.extractall(CST_FOLDER)
- zip_ref.close()
- os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
- os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
- canvas.itemconfigure(message, text='Installation terminée !')
- except Exception as e:
- logger.critical('[updator() thread] : Unable to install the module ! Stopping : ' + str(e))
- showerror("Erreur d'appel de procédure distante", "L'installation du module OCR a échoué, contactez le développeur.")
-
- ret = 11
- else:
- logger.critical('[updator() thread] : Unable to download the module ! ')
- showerror('Erreur de téléchargement', "L'installation du module OCR a échoué, merci d'indiquer le chemin d'accès au fichier tesseract_4 dans la fenêtre suivante")
- path = filedialog.askopenfilename(title="Indiquez le chemin d'accès à tesseract_4...", filetypes=(('Tesseract_4', '*.cni4'),
- ('Tesseract_4', '*.cni4')))
- if path != '':
- try:
- canvas.itemconfigure(message, text='Installation...')
- zip_ref = zipfile.ZipFile(path, 'r')
- zip_ref.extractall(CST_FOLDER)
- zip_ref.close()
- logger.error('[updator() thread] : Manual installation successed')
- canvas.itemconfigure(message, text='Installation terminée !')
- os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
- os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
- except Exception as e:
- logger.error('[updator() thread] : Manual installation has failed' + str(e))
- showerror('Erreur de lecture', "Le module OCR n'a pas pu être installé, la saisie automatique de scans ne pourra donc fonctionner")
-
- else:
- showerror('Opération annulée', "Le module OCR n'a été installé, la saisie automatique de scans ne pourra donc fonctionner")
- except URLExcept.HTTPError as e:
- canvas.itemconfigure(message, text=('Echec de la mise à jour : Erreur HTTP ' + str(e.code) + ' . Préparation du lancement...'))
- logger.error('[updator() thread] : Update has failed with HTTP error' + str(e.code))
- if int(e.code) == 407:
- showerror('Erreur 407', 'Attention : le système de mise à jour automatique a fait face à une erreur 407, signifiant que la connexion au serveur proxy a été refusée. Vos identifiants vous seront redemandés au prochain démarrage. La mise à jour a échoué.')
- logger.info('[updator() thread] : Credential error. Deleting the config file...')
- os.remove(CST_FOLDER + 'conf.ig')
- p.configure(mode='indeterminate', value=0, maximum=20)
- p.start()
- time.sleep(3)
- except Exception as e:
- canvas.itemconfigure(message, text='Echec de la mise à jour. Préparation du lancement...')
- logger.error('[updator() thread] : Error from the updating system : ' + str(e))
- p.configure(mode='indeterminate', value=0, maximum=20)
- p.start()
- time.sleep(2)
-
- p.stop()
- upwin.destroy()
- root.destroy()
- return ret
-
- logger.info('updating() : Launching updator() thread...')
- threading.Thread(target=updator, daemon=True).start()
- logger.info('updating() [Thread] : Ending updator() thread')
-
- ret = 11
- root = Tk()
- root.attributes('-alpha', 0.0)
- root.iconify()
- upwin = Toplevel(root)
- upwin.overrideredirect(1)
- upwin.configure(bg=CST_COLOR)
- upwin.resizable(width=False, height=False)
- w = 600
- h = 300
- upwin.update()
- canvas = Canvas(upwin, width=600, height=270, bg=CST_COLOR, highlightthickness=0)
- pbar = Canvas(upwin, width=600, height=30, bg=CST_COLOR)
- p = ttk.Progressbar(pbar, orient=HORIZONTAL, length=590, mode='determinate')
- upwin.update()
- ws = upwin.winfo_screenwidth()
- hs = upwin.winfo_screenheight()
- canvas.create_text((w / 2), (h / 3), text=(CST_NAME + ' ' + CST_VERTITLE), font='Calibri 30 bold', fill='white')
- message = canvas.create_text((w / 2), (h / 1.15), text=' ', font='Calibri 9', fill='white')
- upwin.update()
- x = ws / 2 - w / 2
- y = hs / 2 - h / 2
- upwin.geometry('%dx%d+%d+%d' % (w, h, x, y))
- canvas.grid()
- pbar.grid()
- p.grid()
- upwin.after(2000, updating)
- if getattr(sys, 'frozen', False):
- root.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
- else:
- root.iconbitmap('id-card.ico')
- logger.info('SoftUpdate() : Entering upwin mainloop()')
- upwin.protocol('WM_DELETE_WINDOW', lambda : root.destroy())
- upwin.mainloop()
- logger.info('SoftUpdate() : Exiting upwin mainloop()')
- if ret == 11:
- logger.info('SoftUpdate() : OK to start to main() normally !')
- return True
- else:
- logger.info('SoftUpdate() : Program will stop !')
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application launcher & updater *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
+
+from CNI_GLOBALVAR import *
+from CNI_classes import *
+import hashlib
+from pypac import PACSession
+from requests.auth import HTTPProxyAuth
+import subprocess
+
+def SoftUpdate(logger):
+ global ret
+ global upwin
+ import zipfile
+ for f in os.listdir(CST_FOLDER):
+ if f[-4:] == '.tif':
+ try:
+ os.remove(CST_FOLDER + '\\' + f)
+ except PermissionError as e:
+ logger.info('SoftUpdate() : Failing to purge : ' + str(e))
+
+ logger.info('SoftUpdate() : Looking for older version in dir...')
+ list = os.listdir('.')
+ for file in list:
+ if file.startswith('CNIRevelator_'):
+ temp = ['0', '0', '0']
+ ver = file[13:].split('.')
+ for i in range(len(ver)):
+ if ver[i] != 'exe':
+ try:
+ temp[i] = ver[i]
+ except:
+ pass
+
+ ver = temp.copy()
+ try:
+ sum_ver = int(ver[0]) * 100 + int(ver[1]) * 10 + int(ver[2])
+ if sum_ver < CST_SUM_VER:
+ if file[-3:] == 'exe':
+ os.remove(file)
+ logger.info('SoftUpdate() : Removed old version : ' + str(file))
+ CST_CHANGELOG.isOn = True
+ except Exception as e:
+ logger.error('SoftUpdate() : Failing to remove old version ' + str(file) + ' : ' + str(e))
+
+ def updating():
+
+ def updator():
+ global ret
+ logger.info('[updator() thread] : Welcome !')
+ ret = 11
+ canvas.itemconfigure(message, text='Recherche de mises-à-jour...')
+ p.configure(mode='indeterminate', value=0, maximum=20)
+ p.start()
+ upwin.update()
+ logger.info('[updator() thread] : Looking for updates...')
+ try:
+
+ def download(url, filename):
+ global key
+ global login
+ try:
+ logger.info('[download() thread] : Trying getting credentials in the config file')
+ with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
+ AESObj = AESCipher(CST_CRYPTOKEY)
+ try:
+ tempone = AESObj.decrypt(config.read())
+ if tempone != '||':
+ if tempone.find('||') != -1:
+ IPN, IPN_PASS = tempone.split('||')[0:2]
+ else:
+ raise ValueError('Cryptokey is bad !')
+ else:
+ IPN = ''
+ IPN_PASS = ''
+ except Exception as e:
+ raise IOError(str(e))
+ else:
+ logger.info('[download() thread] : Got credentials !')
+ session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
+ logger.info('[download() thread] : Authenticated to proxy successfully')
+ except IOError as e:
+ logger.error('[download() thread] : False or absent credentials in the config file : ' + str(e))
+ NoConnect = True
+ while NoConnect:
+
+ class LoginDialog(Toplevel):
+
+ def __init__(self, parent):
+ super().__init__(parent)
+ self.title('Connexion')
+ Label(self, text='IPN : ').pack()
+ self.entry_login = Entry(self)
+ self.entry_login.insert(0, '')
+ self.entry_login.pack()
+ Label(self, text='Mot de passe : ').pack()
+ self.entry_pass = Entry(self, show='*')
+ self.entry_pass.insert(0, '')
+ self.entry_pass.pack()
+ Button(self, text='Connexion', command=(self.connecti)).pack()
+ self.resizable(width=False, height=False)
+ w = 150
+ h = 110
+ self.update()
+ ws = self.winfo_screenwidth()
+ hs = self.winfo_screenheight()
+ if getattr(sys, 'frozen', False):
+ self.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
+ else:
+ self.iconbitmap('id-card.ico')
+ upwin.update()
+ x = ws / 2 - w / 2
+ y = hs / 2 - h / 2
+ self.geometry('%dx%d+%d+%d' % (w, h, x, y))
+
+ def connecti(self):
+ global key
+ global login
+ login = self.entry_login.get().strip()
+ key = self.entry_pass.get().strip()
+ self.destroy()
+
+ session = PACSession()
+ if session.get_pac() == None:
+ IPN = ''
+ IPN_PASS = ''
+ NoConnect = False
+ break
+ canvas.itemconfigure(message, text='En attente de connexion au serveur proxy...')
+ login = ''
+ key = ''
+ result = LoginDialog(upwin)
+ result.transient(upwin)
+ result.grab_set()
+ upwin.wait_window(result)
+ IPN = login
+ IPN_PASS = key
+ session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
+ Ans = session.get('http://www.google.com')
+ if str(Ans) == '':
+ canvas.itemconfigure(message, text='Identifiants erronés, accès refusé')
+ logger.info('[download() thread] : 407 Error')
+ time.sleep(1)
+ else:
+ if str(Ans) == '':
+ logger.info('[download() thread] : Connection ok !')
+ NoConnect = False
+ else:
+ raise IOError()
+
+ AESObj = AESCipher(CST_CRYPTOKEY)
+ with open(CST_FOLDER + 'conf.ig', 'wb+') as (f):
+ logger.info('[download() thread] : Saving credentials in encrypted config file')
+ f.write(AESObj.encrypt(IPN + '||' + IPN_PASS))
+
+ if IPN == 'i005316':
+ canvas.itemconfigure(message, text='Bienvenue Thierry !')
+ else:
+ if IPN == 'i020251':
+ canvas.itemconfigure(message, text='Bienvenue Samia !')
+ else:
+ if IPN == 'i018410':
+ canvas.itemconfigure(message, text='Bienvenue Adrien !')
+ else:
+ if IPN == 'i003067':
+ canvas.itemconfigure(message, text='Bienvenue Remy !')
+ else:
+ if IPN == 'i018422':
+ canvas.itemconfigure(message, text='Bienvenue Eloise !')
+ time.sleep(1)
+ try:
+ Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
+ PROXY_USABLE = Prox_us[6:-1].split(';')[0]
+ proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
+ ph = urllib2.ProxyHandler({'http': proxy_server_url})
+ auth = urllib2.ProxyBasicAuthHandler()
+ server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
+ urllib2.install_opener(server)
+ logger.info('[download() thread] : Proxy connection initiated successfully')
+ except:
+ logger.info('[download() thread] : Proxy connection not initiated')
+
+ try:
+ urllib2.urlretrieve(url, filename)
+ return True
+ except Exception as e:
+ logger.error('[download() thread] : HTTP ERROR ')
+ return e
+
+ logger.info('[updator() thread] : Prepare downloading the version recap file...')
+ tempfile = CST_FOLDER + 'temp' + str(random.randint(11111, 99999)) + '.cniu'
+ isOk = download(CST_LINK + 'cnir.ver', tempfile)
+ if not isOk:
+ raise isOk
+ urllib2.urlcleanup()
+ logger.info('[updator() thread] : Opening version recap file...')
+ file_ver = open(tempfile, 'r')
+ logger.info('[updator() thread] : Reading version recap file...')
+ version = file_ver.read()
+ logger.info('[updator() thread] : Closing version recap file...')
+ repert = version.split('|')
+ file_ver.close()
+ logger.info('[updator() thread] : Deleting version recap file...')
+ os.remove(tempfile)
+ logger.info('[updator() thread] : Parsing informations about version...')
+ final_f = 'CNI_file'
+ final_ver = ['0', '0', '0']
+ final_hash = ''
+ for sentence in repert:
+ try:
+ file, hashref = sentence.split(':')
+ except ValueError:
+ pass
+ else:
+ if str.startswith(file, CST_NAME):
+ ver = file.replace(CST_NAME + '_', '').split('.')
+ temp = [
+ '0', '0', '0']
+ for i in range(len(ver)):
+ temp[i] = ver[i]
+
+ ver = temp.copy()
+ sum_fver = int(final_ver[0]) * 100 + int(final_ver[1]) * 10 + int(final_ver[2])
+ sum_ver = int(ver[0]) * 100 + int(ver[1]) * 10 + int(ver[2])
+ if sum_ver > sum_fver:
+ final_ver = ver.copy()
+ final_f = file
+ final_hash = hashref
+
+ sum_ver = int(final_ver[0]) * 100 + int(final_ver[1]) * 10 + int(final_ver[2])
+ if final_f != 'CNI_file':
+ if sum_ver > CST_SUM_VER:
+ logger.info('[updator() thread] : New version of CNIRevelator found !')
+ canvas.itemconfigure(message, text='Mise à jour disponible ! Préparation du téléchargement...')
+ logger.info('[updator() thread] : Preparing download')
+ with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
+ logger.info('[updator() thread] : Reading credentials for proxy in config file...')
+ AESObj = AESCipher(CST_CRYPTOKEY)
+ IPN, IPN_PASS = AESObj.decrypt(config.read()).split('||')[0:2]
+ session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
+ try:
+ Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
+ PROXY_USABLE = Prox_us[6:-1].split(';')[0]
+ proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
+ ph = urllib2.ProxyHandler({'http': proxy_server_url})
+ auth = urllib2.ProxyBasicAuthHandler()
+ server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
+ logger.info('[updator() thread] : Connection to the proxy initiated successfully !')
+ except:
+ canvas.itemconfigure(message, text='Téléchargement en connexion directe...')
+ server = urllib2.build_opener()
+ logger.info('[updator() thread] : Direct connection initiated successfully')
+
+ logger.info('[updator() thread] : Launching download of ' + final_f)
+ Statut = Download(CST_LINK + final_f, final_f, final_f, server, p, canvas, message, logger)
+ BLOCKSIZE = 65536
+ hasher = hashlib.sha1()
+ try:
+ with open(final_f, 'rb') as (afile):
+ buf = afile.read(BLOCKSIZE)
+ while len(buf) > 0:
+ hasher.update(buf)
+ buf = afile.read(BLOCKSIZE)
+
+ hashcod = hasher.hexdigest()
+ if hashcod != final_hash:
+ Statut.success = False
+ logger.error('[updator() thread] : Hashcode Error :' + final_f)
+ try:
+ os.remove(final_f)
+ except IOError:
+ pass
+
+ else:
+ logger.info('[updator() thread] : Hashcode pass :' + final_f)
+ except FileNotFoundError as e:
+ logger.error('[updator() thread] : File not found ' + final_f)
+
+ if Statut.success:
+ try:
+ os.rename(final_f, final_f + '.exe')
+ except IOError:
+ logger.error('[updator() thread] : Unable to rename the file ! Wait 3 sec and retry')
+ time.sleep(3)
+ try:
+ os.rename(final_f, final_f + '.exe')
+ except IOError:
+ logger.critical('[updator() thread] : Unable to rename the file !')
+
+ else:
+ canvas.itemconfigure(message, text='Téléchargement terminé ! Préparation du lancement...')
+ logger.info('[updator() thread] : Download of ' + final_f + 'finished successfully')
+ p.configure(mode='indeterminate', value=0, maximum=20)
+ p.start()
+ time.sleep(1)
+ logger.info('[updator() thread] : Launching ' + final_f)
+ try:
+ proc = subprocess.Popen((final_f + '.exe'), shell=False, stdin=None, stdout=None, stderr=None, close_fds=True)
+ except:
+ logger.error('[updator() thread] : Unable to start the new version ! Wait 3 sec and retry')
+ time.sleep(3)
+ try:
+ proc = subprocess.Popen((final_f + '.exe'), shell=False, stdin=None, stdout=None, stderr=None, close_fds=True)
+ except Exception as e:
+ logger.critical('[updator() thread] : Unable to start the new version ! Stopping : ' + str(e))
+ showerror("Erreur d'appel de procédure distante", 'Le lancement du nouveau programme a échoué, vous devez le lancer manuellement une fois cette fenêtre fermée', parent=upwin)
+
+ ret = 12
+ else:
+ canvas.itemconfigure(message, text='Echec de la mise à jour : Erreur HTTP. Préparation du lancement...')
+ logger.error('[updator() thread] : Update has failed with HTTP error')
+ time.sleep(1)
+ canvas.itemconfigure(message, text='Logiciel déjà à jour. Préparation du lancement...')
+ logger.info('[updator() thread] : CNIRevelator is up to date !')
+ time.sleep(1)
+ ret = 11
+ if os.path.exists(CST_FOLDER + 'Tesseract-OCR4\\tesseract.exe'):
+ os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
+ os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
+ else:
+ final_f = 'tesseract_4'
+ logger.info('[updator() thread] : Downloading tesseract 4 !')
+ canvas.itemconfigure(message, text='Mise à jour du module OCR ! Préparation du téléchargement...')
+ logger.info('[updator() thread] : Preparing download')
+ with open(CST_FOLDER + 'conf.ig', 'rb') as (config):
+ logger.info('[updator() thread] : Reading credentials for proxy in config file...')
+ AESObj = AESCipher(CST_CRYPTOKEY)
+ IPN, IPN_PASS = AESObj.decrypt(config.read()).split('||')[0:2]
+ session = PACSession(proxy_auth=(HTTPProxyAuth(IPN, IPN_PASS)))
+ try:
+ Prox_us = session.get_pac().find_proxy_for_url(CST_LINK, 'neoxgroup.eu')
+ PROXY_USABLE = Prox_us[6:-1].split(';')[0]
+ proxy_server_url = IPN + ':' + IPN_PASS + '@' + PROXY_USABLE
+ ph = urllib2.ProxyHandler({'http': proxy_server_url})
+ auth = urllib2.ProxyBasicAuthHandler()
+ server = urllib2.build_opener(ph, auth, urllib2.HTTPHandler)
+ logger.info('[updator() thread] : Connection to the proxy initiated successfully !')
+ except:
+ canvas.itemconfigure(message, text='Téléchargement en connexion directe...')
+ server = urllib2.build_opener()
+ logger.info('[updator() thread] : Direct connection initiated successfully')
+
+ logger.info('[updator() thread] : Launching download of ' + final_f)
+ Statut = Download(CST_LINK + final_f, CST_FOLDER + final_f, final_f, server, p, canvas, message, logger)
+ hashcod = ''
+ logger.info('[updator() thread] : Verifying hashcode of ' + final_f)
+ BLOCKSIZE = 65536
+ hasher = hashlib.sha1()
+ try:
+ with open(CST_FOLDER + final_f, 'rb') as (afile):
+ buf = afile.read(BLOCKSIZE)
+ while len(buf) > 0:
+ hasher.update(buf)
+ buf = afile.read(BLOCKSIZE)
+
+ hashcod = hasher.hexdigest()
+ if hashcod != CST_TesserHash:
+ Statut.success = False
+ logger.error('[updator() thread] : Hashcode Error : ' + final_f)
+ try:
+ os.remove(CST_FOLDER + final_f)
+ except IOError:
+ pass
+
+ else:
+ logger.info('[updator() thread] : Hashcode pass : ' + final_f)
+ except FileNotFoundError as e:
+ logger.error('[updator() thread] : File not found ' + final_f)
+
+ if Statut.success:
+ canvas.itemconfigure(message, text='Téléchargement terminé ! Installation...')
+ logger.info('[updator() thread] : Download of ' + final_f + 'finished successfully')
+ p.configure(mode='indeterminate', value=0, maximum=20)
+ p.start()
+ try:
+ zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
+ zip_ref.extractall(CST_FOLDER)
+ zip_ref.close()
+ os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
+ os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
+ canvas.itemconfigure(message, text='Installation terminée !')
+ except:
+ logger.error('[updator() thread] : Unable to install the module. Wait and retry')
+ time.sleep(3)
+ try:
+ zip_ref = zipfile.ZipFile(CST_FOLDER + final_f, 'r')
+ zip_ref.extractall(CST_FOLDER)
+ zip_ref.close()
+ os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
+ os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
+ canvas.itemconfigure(message, text='Installation terminée !')
+ except Exception as e:
+ logger.critical('[updator() thread] : Unable to install the module ! Stopping : ' + str(e))
+ showerror("Erreur d'appel de procédure distante", "L'installation du module OCR a échoué, contactez le développeur.")
+
+ ret = 11
+ else:
+ logger.critical('[updator() thread] : Unable to download the module ! ')
+ showerror('Erreur de téléchargement', "L'installation du module OCR a échoué, merci d'indiquer le chemin d'accès au fichier tesseract_4 dans la fenêtre suivante")
+ path = filedialog.askopenfilename(title="Indiquez le chemin d'accès à tesseract_4...", filetypes=(('Tesseract_4', '*.cni4'),
+ ('Tesseract_4', '*.cni4')))
+ if path != '':
+ try:
+ canvas.itemconfigure(message, text='Installation...')
+ zip_ref = zipfile.ZipFile(path, 'r')
+ zip_ref.extractall(CST_FOLDER)
+ zip_ref.close()
+ logger.error('[updator() thread] : Manual installation successed')
+ canvas.itemconfigure(message, text='Installation terminée !')
+ os.environ['PATH'] = CST_FOLDER + 'Tesseract-OCR4\\'
+ os.environ['TESSDATA_PREFIX'] = CST_FOLDER + 'Tesseract-OCR4\\tessdata'
+ except Exception as e:
+ logger.error('[updator() thread] : Manual installation has failed' + str(e))
+ showerror('Erreur de lecture', "Le module OCR n'a pas pu être installé, la saisie automatique de scans ne pourra donc fonctionner")
+
+ else:
+ showerror('Opération annulée', "Le module OCR n'a été installé, la saisie automatique de scans ne pourra donc fonctionner")
+ except URLExcept.HTTPError as e:
+ canvas.itemconfigure(message, text=('Echec de la mise à jour : Erreur HTTP ' + str(e.code) + ' . Préparation du lancement...'))
+ logger.error('[updator() thread] : Update has failed with HTTP error' + str(e.code))
+ if int(e.code) == 407:
+ showerror('Erreur 407', 'Attention : le système de mise à jour automatique a fait face à une erreur 407, signifiant que la connexion au serveur proxy a été refusée. Vos identifiants vous seront redemandés au prochain démarrage. La mise à jour a échoué.')
+ logger.info('[updator() thread] : Credential error. Deleting the config file...')
+ os.remove(CST_FOLDER + 'conf.ig')
+ p.configure(mode='indeterminate', value=0, maximum=20)
+ p.start()
+ time.sleep(3)
+ except Exception as e:
+ canvas.itemconfigure(message, text='Echec de la mise à jour. Préparation du lancement...')
+ logger.error('[updator() thread] : Error from the updating system : ' + str(e))
+ p.configure(mode='indeterminate', value=0, maximum=20)
+ p.start()
+ time.sleep(2)
+
+ p.stop()
+ upwin.destroy()
+ root.destroy()
+ return ret
+
+ logger.info('updating() : Launching updator() thread...')
+ threading.Thread(target=updator, daemon=True).start()
+ logger.info('updating() [Thread] : Ending updator() thread')
+
+ ret = 11
+ root = Tk()
+ root.attributes('-alpha', 0.0)
+ root.iconify()
+ upwin = Toplevel(root)
+ upwin.overrideredirect(1)
+ upwin.configure(bg=CST_COLOR)
+ upwin.resizable(width=False, height=False)
+ w = 600
+ h = 300
+ upwin.update()
+ canvas = Canvas(upwin, width=600, height=270, bg=CST_COLOR, highlightthickness=0)
+ pbar = Canvas(upwin, width=600, height=30, bg=CST_COLOR)
+ p = ttk.Progressbar(pbar, orient=HORIZONTAL, length=590, mode='determinate')
+ upwin.update()
+ ws = upwin.winfo_screenwidth()
+ hs = upwin.winfo_screenheight()
+ canvas.create_text((w / 2), (h / 3), text=(CST_NAME + ' ' + CST_VERTITLE), font='Calibri 30 bold', fill='white')
+ message = canvas.create_text((w / 2), (h / 1.15), text=' ', font='Calibri 9', fill='white')
+ upwin.update()
+ x = ws / 2 - w / 2
+ y = hs / 2 - h / 2
+ upwin.geometry('%dx%d+%d+%d' % (w, h, x, y))
+ canvas.grid()
+ pbar.grid()
+ p.grid()
+ upwin.after(2000, updating)
+ if getattr(sys, 'frozen', False):
+ root.iconbitmap(sys._MEIPASS + '\\id-card.ico\\id-card.ico')
+ else:
+ root.iconbitmap('id-card.ico')
+ logger.info('SoftUpdate() : Entering upwin mainloop()')
+ upwin.protocol('WM_DELETE_WINDOW', lambda : root.destroy())
+ upwin.mainloop()
+ logger.info('SoftUpdate() : Exiting upwin mainloop()')
+ if ret == 11:
+ logger.info('SoftUpdate() : OK to start to main() normally !')
+ return True
+ else:
+ logger.info('SoftUpdate() : Program will stop !')
return False
\ No newline at end of file
diff --git a/CNI_classes.py b/src/analyzer/CNI_classes.py
similarity index 97%
rename from CNI_classes.py
rename to src/analyzer/CNI_classes.py
index abf27a3..18695a3 100644
--- a/CNI_classes.py
+++ b/src/analyzer/CNI_classes.py
@@ -1,15 +1,28 @@
"""
-********************************************************************************
- *** Projet CNI_Revelator ***
-
- GNU GPL * 07/2018
-
- Adrien Bourmault
-
- CLASSES
-
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application launcher & updater *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
********************************************************************************
"""
+
from CNI_GLOBALVAR import *
from PIL import Image, ImageFont, ImageDraw, ImageTk, ImageEnhance, ImageFilter
import math, warnings, string
diff --git a/CNI_pytesseract.py b/src/analyzer/CNI_pytesseract.py
similarity index 83%
rename from CNI_pytesseract.py
rename to src/analyzer/CNI_pytesseract.py
index 27f5319..ba023a5 100644
--- a/CNI_pytesseract.py
+++ b/src/analyzer/CNI_pytesseract.py
@@ -1,311 +1,326 @@
-"""
-********************************************************************************
- *** Projet CNI_Revelator ***
-
- GNU GPL * 07/2018
-
- Adrien Bourmault
-
- Pytesseract modification to comply with Pyinstaller
-
-*****
-"""
-try:
- import Image
-except ImportError:
- from PIL import Image
-
-import os, sys, subprocess, tempfile, shlex, string
-from glob import iglob
-from pkgutil import find_loader
-from distutils.version import LooseVersion
-from os.path import realpath, normpath, normcase
-numpy_installed = find_loader('numpy') is not None
-if numpy_installed:
- from numpy import ndarray
-tesseract_cmd = 'tesseract'
-RGB_MODE = 'RGB'
-OSD_KEYS = {'Page number':(
- 'page_num', int),
- 'Orientation in degrees':(
- 'orientation', int),
- 'Rotate':(
- 'rotate', int),
- 'Orientation confidence':(
- 'orientation_conf', float),
- 'Script':(
- 'script', str),
- 'Script confidence':(
- 'script_conf', float)}
-
-class Output:
- STRING = 'string'
- BYTES = 'bytes'
- DICT = 'dict'
-
-
-class TesseractError(RuntimeError):
-
- def __init__(self, status, message):
- self.status = status
- self.message = message
- self.args = (status, message)
-
-
-class TesseractNotFoundError(EnvironmentError):
-
- def __init__(self):
- super(TesseractNotFoundError, self).__init__(tesseract_cmd + " is not installed or it's not in your path")
-
-
-class TSVNotSupported(EnvironmentError):
-
- def __init__(self):
- super(TSVNotSupported, self).__init__('TSV output not supported. Tesseract >= 3.05 required')
-
-
-def run_once(func):
-
- def wrapper(*args, **kwargs):
- if wrapper._result is wrapper:
- wrapper._result = func(*args, **kwargs)
- return wrapper._result
-
- wrapper._result = wrapper
- return wrapper
-
-
-def get_errors(error_string):
- return ' '.join(line for line in error_string.decode('utf-8').splitlines()).strip()
-
-
-def cleanup(temp_name):
- """ Tries to remove files by filename wildcard path. """
- for filename in iglob(temp_name + '*' if temp_name else temp_name):
- try:
- os.remove(filename)
- except OSError:
- pass
-
-
-def prepare(image):
- if isinstance(image, Image.Image):
- return image
- if numpy_installed:
- if isinstance(image, ndarray):
- pass
- return Image.fromarray(image)
- raise TypeError('Unsupported image object')
-
-
-def save_image(image):
- temp_name = tempfile.mktemp(prefix='tess_')
- if isinstance(image, str):
- return (temp_name, realpath(normpath(normcase(image))))
- else:
- image = prepare(image)
- img_extension = image.format
- if image.format not in frozenset({'BMP', 'JPEG', 'GIF', 'TIFF', 'PNG'}):
- img_extension = 'PNG'
- if not image.mode.startswith(RGB_MODE):
- image = image.convert(RGB_MODE)
- if 'A' in image.getbands():
- background = Image.new(RGB_MODE, image.size, (255, 255, 255))
- background.paste(image, (0, 0), image)
- image = background
- input_file_name = temp_name + os.extsep + img_extension
- (image.save)(input_file_name, format=img_extension, **image.info)
- return (
- temp_name, input_file_name)
-
-
-def subprocess_args(include_stdout=True):
- if hasattr(subprocess, 'STARTUPINFO'):
- si = subprocess.STARTUPINFO()
- si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
- env = os.environ
- else:
- si = None
- env = None
- if include_stdout:
- ret = {'stdout': subprocess.PIPE}
- else:
- ret = {}
- ret.update({'stdin':subprocess.PIPE, 'stderr':subprocess.PIPE,
- 'startupinfo':si,
- 'env':env})
- return ret
-
-
-def run_tesseract(input_filename, output_filename_base, extension, lang, config='', nice=0):
- cmd_args = []
- if not sys.platform.startswith('win32'):
- if nice != 0:
- cmd_args += ('nice', '-n', str(nice))
- cmd_args += (tesseract_cmd, input_filename, output_filename_base)
- if lang is not None:
- cmd_args += ('-l', lang)
- cmd_args += shlex.split(config)
- if extension not in ('box', 'osd', 'tsv'):
- cmd_args.append(extension)
- try:
- proc = (subprocess.Popen)(cmd_args, **subprocess_args())
- except OSError:
- raise TesseractNotFoundError()
-
- status_code, error_string = proc.wait(), proc.stderr.read()
- proc.stderr.close()
- if status_code:
- raise TesseractError(status_code, get_errors(error_string))
- return True
-
-
-def run_and_get_output(image, extension, lang=None, config='', nice=0, return_bytes=False):
- temp_name, input_filename = ('', '')
- try:
- temp_name, input_filename = save_image(image)
- kwargs = {'input_filename':input_filename,
- 'output_filename_base':temp_name + '_out',
- 'extension':extension,
- 'lang':lang,
- 'config':config,
- 'nice':nice}
- run_tesseract(**kwargs)
- filename = kwargs['output_filename_base'] + os.extsep + extension
- with open(filename, 'rb') as (output_file):
- if return_bytes:
- return output_file.read()
- return output_file.read().decode('utf-8').strip()
- finally:
- cleanup(temp_name)
-
-
-def file_to_dict(tsv, cell_delimiter, str_col_idx):
- result = {}
- rows = [row.split(cell_delimiter) for row in tsv.split('\n')]
- if not rows:
- return result
- else:
- header = rows.pop(0)
- if len(rows[(-1)]) < len(header):
- rows[(-1)].append('')
- if str_col_idx < 0:
- str_col_idx += len(header)
- for i, head in enumerate(header):
- result[head] = [int(row[i]) if i != str_col_idx else row[i] for row in rows]
-
- return result
-
-
-def is_valid(val, _type):
- if _type is int:
- return val.isdigit()
- else:
- if _type is float:
- pass
- try:
- float(val)
- return True
- except ValueError:
- return False
-
- return True
-
-
-def osd_to_dict(osd):
- return {OSD_KEYS[kv[0]][0]:OSD_KEYS[kv[0]][1](kv[1]) for kv in (line.split(': ') for line in osd.split('\n')) if len(kv) == 2 if is_valid(kv[1], OSD_KEYS[kv[0]][1])}
-
-
-@run_once
-def get_tesseract_version():
- """
- Returns LooseVersion object of the Tesseract version
- """
- try:
- return LooseVersion((subprocess.check_output)([tesseract_cmd, '--version'], **subprocess_args(False)).decode('utf-8').split()[1].lstrip(string.printable[10:]))
- except OSError:
- raise TesseractNotFoundError()
-
-
-def image_to_string(image, lang=None, config='', nice=0, boxes=False, output_type=Output.STRING):
- """
- Returns the result of a Tesseract OCR run on the provided image to string
- """
- if boxes:
- print("\nWarning: Argument 'boxes' is deprecated and will be removed in future versions. Use function image_to_boxes instead.\n")
- return image_to_boxes(image, lang, config, nice, output_type)
- else:
- args = [
- image, 'txt', lang, config, nice]
- if output_type == Output.DICT:
- return {'text': run_and_get_output(*args)}
- if output_type == Output.BYTES:
- args.append(True)
- return run_and_get_output(*args)
-
-
-def image_to_boxes(image, lang=None, config='', nice=0, output_type=Output.STRING):
- """
- Returns string containing recognized characters and their box boundaries
- """
- config += ' batch.nochop makebox'
- args = [image, 'box', lang, config, nice]
- if output_type == Output.DICT:
- box_header = 'char left bottom right top page\n'
- return file_to_dict(box_header + run_and_get_output(*args), ' ', 0)
- else:
- if output_type == Output.BYTES:
- args.append(True)
- return run_and_get_output(*args)
-
-
-def image_to_data(image, lang=None, config='', nice=0, output_type=Output.STRING):
- """
- Returns string containing box boundaries, confidences,
- and other information. Requires Tesseract 3.05+
- """
- if get_tesseract_version() < '3.05':
- raise TSVNotSupported()
- config = '{} {}'.format('-c tessedit_create_tsv=1', config.strip()).strip()
- args = [image, 'tsv', lang, config, nice]
- if output_type == Output.DICT:
- return file_to_dict(run_and_get_output(*args), '\t', -1)
- else:
- if output_type == Output.BYTES:
- args.append(True)
- return run_and_get_output(*args)
-
-
-def image_to_osd(image, lang='osd', config='', nice=0, output_type=Output.STRING):
- """
- Returns string containing the orientation and script detection (OSD)
- """
- config = '{}-psm 0 {}'.format('' if get_tesseract_version() < '3.05' else '-', config.strip()).strip()
- args = [
- image, 'osd', lang, config, nice]
- if output_type == Output.DICT:
- return osd_to_dict(run_and_get_output(*args))
- else:
- if output_type == Output.BYTES:
- args.append(True)
- return run_and_get_output(*args)
-
-
-def main():
- if len(sys.argv) == 2:
- filename, lang = sys.argv[1], None
- else:
- if len(sys.argv) == 4:
- if sys.argv[1] == '-l':
- filename, lang = sys.argv[3], sys.argv[2]
- sys.stderr.write('Usage: python pytesseract.py [-l lang] input_file\n')
- exit(2)
- try:
- print(image_to_string((Image.open(filename)), lang=lang))
- except IOError:
- sys.stderr.write('ERROR: Could not open file "%s"\n' % filename)
- exit(1)
-
-
-if __name__ == '__main__':
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Pytesseract modification to comply with Pyinstaller *
+* *
+* Copyright © 2017-2018 Matthias A. Lee (madmaze) *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
+
+
+try:
+ import Image
+except ImportError:
+ from PIL import Image
+
+import os, sys, subprocess, tempfile, shlex, string
+from glob import iglob
+from pkgutil import find_loader
+from distutils.version import LooseVersion
+from os.path import realpath, normpath, normcase
+numpy_installed = find_loader('numpy') is not None
+if numpy_installed:
+ from numpy import ndarray
+tesseract_cmd = 'tesseract'
+RGB_MODE = 'RGB'
+OSD_KEYS = {'Page number':(
+ 'page_num', int),
+ 'Orientation in degrees':(
+ 'orientation', int),
+ 'Rotate':(
+ 'rotate', int),
+ 'Orientation confidence':(
+ 'orientation_conf', float),
+ 'Script':(
+ 'script', str),
+ 'Script confidence':(
+ 'script_conf', float)}
+
+class Output:
+ STRING = 'string'
+ BYTES = 'bytes'
+ DICT = 'dict'
+
+
+class TesseractError(RuntimeError):
+
+ def __init__(self, status, message):
+ self.status = status
+ self.message = message
+ self.args = (status, message)
+
+
+class TesseractNotFoundError(EnvironmentError):
+
+ def __init__(self):
+ super(TesseractNotFoundError, self).__init__(tesseract_cmd + " is not installed or it's not in your path")
+
+
+class TSVNotSupported(EnvironmentError):
+
+ def __init__(self):
+ super(TSVNotSupported, self).__init__('TSV output not supported. Tesseract >= 3.05 required')
+
+
+def run_once(func):
+
+ def wrapper(*args, **kwargs):
+ if wrapper._result is wrapper:
+ wrapper._result = func(*args, **kwargs)
+ return wrapper._result
+
+ wrapper._result = wrapper
+ return wrapper
+
+
+def get_errors(error_string):
+ return ' '.join(line for line in error_string.decode('utf-8').splitlines()).strip()
+
+
+def cleanup(temp_name):
+ """ Tries to remove files by filename wildcard path. """
+ for filename in iglob(temp_name + '*' if temp_name else temp_name):
+ try:
+ os.remove(filename)
+ except OSError:
+ pass
+
+
+def prepare(image):
+ if isinstance(image, Image.Image):
+ return image
+ if numpy_installed:
+ if isinstance(image, ndarray):
+ pass
+ return Image.fromarray(image)
+ raise TypeError('Unsupported image object')
+
+
+def save_image(image):
+ temp_name = tempfile.mktemp(prefix='tess_')
+ if isinstance(image, str):
+ return (temp_name, realpath(normpath(normcase(image))))
+ else:
+ image = prepare(image)
+ img_extension = image.format
+ if image.format not in frozenset({'BMP', 'JPEG', 'GIF', 'TIFF', 'PNG'}):
+ img_extension = 'PNG'
+ if not image.mode.startswith(RGB_MODE):
+ image = image.convert(RGB_MODE)
+ if 'A' in image.getbands():
+ background = Image.new(RGB_MODE, image.size, (255, 255, 255))
+ background.paste(image, (0, 0), image)
+ image = background
+ input_file_name = temp_name + os.extsep + img_extension
+ (image.save)(input_file_name, format=img_extension, **image.info)
+ return (
+ temp_name, input_file_name)
+
+
+def subprocess_args(include_stdout=True):
+ if hasattr(subprocess, 'STARTUPINFO'):
+ si = subprocess.STARTUPINFO()
+ si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ env = os.environ
+ else:
+ si = None
+ env = None
+ if include_stdout:
+ ret = {'stdout': subprocess.PIPE}
+ else:
+ ret = {}
+ ret.update({'stdin':subprocess.PIPE, 'stderr':subprocess.PIPE,
+ 'startupinfo':si,
+ 'env':env})
+ return ret
+
+
+def run_tesseract(input_filename, output_filename_base, extension, lang, config='', nice=0):
+ cmd_args = []
+ if not sys.platform.startswith('win32'):
+ if nice != 0:
+ cmd_args += ('nice', '-n', str(nice))
+ cmd_args += (tesseract_cmd, input_filename, output_filename_base)
+ if lang is not None:
+ cmd_args += ('-l', lang)
+ cmd_args += shlex.split(config)
+ if extension not in ('box', 'osd', 'tsv'):
+ cmd_args.append(extension)
+ try:
+ proc = (subprocess.Popen)(cmd_args, **subprocess_args())
+ except OSError:
+ raise TesseractNotFoundError()
+
+ status_code, error_string = proc.wait(), proc.stderr.read()
+ proc.stderr.close()
+ if status_code:
+ raise TesseractError(status_code, get_errors(error_string))
+ return True
+
+
+def run_and_get_output(image, extension, lang=None, config='', nice=0, return_bytes=False):
+ temp_name, input_filename = ('', '')
+ try:
+ temp_name, input_filename = save_image(image)
+ kwargs = {'input_filename':input_filename,
+ 'output_filename_base':temp_name + '_out',
+ 'extension':extension,
+ 'lang':lang,
+ 'config':config,
+ 'nice':nice}
+ run_tesseract(**kwargs)
+ filename = kwargs['output_filename_base'] + os.extsep + extension
+ with open(filename, 'rb') as (output_file):
+ if return_bytes:
+ return output_file.read()
+ return output_file.read().decode('utf-8').strip()
+ finally:
+ cleanup(temp_name)
+
+
+def file_to_dict(tsv, cell_delimiter, str_col_idx):
+ result = {}
+ rows = [row.split(cell_delimiter) for row in tsv.split('\n')]
+ if not rows:
+ return result
+ else:
+ header = rows.pop(0)
+ if len(rows[(-1)]) < len(header):
+ rows[(-1)].append('')
+ if str_col_idx < 0:
+ str_col_idx += len(header)
+ for i, head in enumerate(header):
+ result[head] = [int(row[i]) if i != str_col_idx else row[i] for row in rows]
+
+ return result
+
+
+def is_valid(val, _type):
+ if _type is int:
+ return val.isdigit()
+ else:
+ if _type is float:
+ pass
+ try:
+ float(val)
+ return True
+ except ValueError:
+ return False
+
+ return True
+
+
+def osd_to_dict(osd):
+ return {OSD_KEYS[kv[0]][0]:OSD_KEYS[kv[0]][1](kv[1]) for kv in (line.split(': ') for line in osd.split('\n')) if len(kv) == 2 if is_valid(kv[1], OSD_KEYS[kv[0]][1])}
+
+
+@run_once
+def get_tesseract_version():
+ """
+ Returns LooseVersion object of the Tesseract version
+ """
+ try:
+ return LooseVersion((subprocess.check_output)([tesseract_cmd, '--version'], **subprocess_args(False)).decode('utf-8').split()[1].lstrip(string.printable[10:]))
+ except OSError:
+ raise TesseractNotFoundError()
+
+
+def image_to_string(image, lang=None, config='', nice=0, boxes=False, output_type=Output.STRING):
+ """
+ Returns the result of a Tesseract OCR run on the provided image to string
+ """
+ if boxes:
+ print("\nWarning: Argument 'boxes' is deprecated and will be removed in future versions. Use function image_to_boxes instead.\n")
+ return image_to_boxes(image, lang, config, nice, output_type)
+ else:
+ args = [
+ image, 'txt', lang, config, nice]
+ if output_type == Output.DICT:
+ return {'text': run_and_get_output(*args)}
+ if output_type == Output.BYTES:
+ args.append(True)
+ return run_and_get_output(*args)
+
+
+def image_to_boxes(image, lang=None, config='', nice=0, output_type=Output.STRING):
+ """
+ Returns string containing recognized characters and their box boundaries
+ """
+ config += ' batch.nochop makebox'
+ args = [image, 'box', lang, config, nice]
+ if output_type == Output.DICT:
+ box_header = 'char left bottom right top page\n'
+ return file_to_dict(box_header + run_and_get_output(*args), ' ', 0)
+ else:
+ if output_type == Output.BYTES:
+ args.append(True)
+ return run_and_get_output(*args)
+
+
+def image_to_data(image, lang=None, config='', nice=0, output_type=Output.STRING):
+ """
+ Returns string containing box boundaries, confidences,
+ and other information. Requires Tesseract 3.05+
+ """
+ if get_tesseract_version() < '3.05':
+ raise TSVNotSupported()
+ config = '{} {}'.format('-c tessedit_create_tsv=1', config.strip()).strip()
+ args = [image, 'tsv', lang, config, nice]
+ if output_type == Output.DICT:
+ return file_to_dict(run_and_get_output(*args), '\t', -1)
+ else:
+ if output_type == Output.BYTES:
+ args.append(True)
+ return run_and_get_output(*args)
+
+
+def image_to_osd(image, lang='osd', config='', nice=0, output_type=Output.STRING):
+ """
+ Returns string containing the orientation and script detection (OSD)
+ """
+ config = '{}-psm 0 {}'.format('' if get_tesseract_version() < '3.05' else '-', config.strip()).strip()
+ args = [
+ image, 'osd', lang, config, nice]
+ if output_type == Output.DICT:
+ return osd_to_dict(run_and_get_output(*args))
+ else:
+ if output_type == Output.BYTES:
+ args.append(True)
+ return run_and_get_output(*args)
+
+
+def main():
+ if len(sys.argv) == 2:
+ filename, lang = sys.argv[1], None
+ else:
+ if len(sys.argv) == 4:
+ if sys.argv[1] == '-l':
+ filename, lang = sys.argv[3], sys.argv[2]
+ sys.stderr.write('Usage: python pytesseract.py [-l lang] input_file\n')
+ exit(2)
+ try:
+ print(image_to_string((Image.open(filename)), lang=lang))
+ except IOError:
+ sys.stderr.write('ERROR: Could not open file "%s"\n' % filename)
+ exit(1)
+
+
+if __name__ == '__main__':
main()
\ No newline at end of file
diff --git a/src/launcher/CNIRLauncher.py b/src/launcher/CNIRLauncher.py
new file mode 100644
index 0000000..68765fd
--- /dev/null
+++ b/src/launcher/CNIRLauncher.py
@@ -0,0 +1,34 @@
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application launcher & updater main file *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
+
+import logger
+
+## Launching the launcher
+
+# Creating a log file
+logfile = logger.NewLoggingSystem()
+
+# Hello world
+logfile.printdbg('*** CNIRLauncher LOGFILE. Hello World ! ***')
diff --git a/src/launcher/downloader.py b/src/launcher/downloader.py
new file mode 100644
index 0000000..f6032d4
--- /dev/null
+++ b/src/launcher/downloader.py
@@ -0,0 +1,24 @@
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application launcher download stuff *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
\ No newline at end of file
diff --git a/src/launcher/globs.py b/src/launcher/globs.py
new file mode 100644
index 0000000..3375a25
--- /dev/null
+++ b/src/launcher/globs.py
@@ -0,0 +1,29 @@
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application launcher global variables *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
+import os
+
+CNIRTesserHash = '5b58db27f7bc08c58a2cb33d01533b034b067cf8'
+#CNIRFolder = os.getenv('APPDATA') + '/CNIRevelator/'
+CNIRFolder = '.'
\ No newline at end of file
diff --git a/src/launcher/logger.py b/src/launcher/logger.py
new file mode 100644
index 0000000..d2e1af4
--- /dev/null
+++ b/src/launcher/logger.py
@@ -0,0 +1,59 @@
+"""
+********************************************************************************
+* CNIRevelator *
+* *
+* Desc: Application launcher logging stuff *
+* *
+* Copyright © 2018-2019 Adrien Bourmault (neox95) *
+* *
+* This file is part of CNIRevelator. *
+* *
+* CNIRevelator is free software: you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation, either version 3 of the License, or *
+* any later version. *
+* *
+* CNIRevelator is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY*without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with CNIRevelator. If not, see . *
+********************************************************************************
+"""
+## The logging class
+
+import logging
+import globs
+
+class NewLoggingSystem:
+
+ def __init__(self):
+
+ # Deleting the error log
+ try:
+ os.remove(globs.CNIRFolder + '\\error.log') # The deletion does not working
+ except:
+ pass
+
+ # Create new logging handle
+ logger = logging.getLogger()
+ logger.setLevel(logging.INFO) # To make sure we can have a debug channel
+
+ # Create channels
+ formatter = logging.Formatter('[ %(module)s/%(funcName)s ] %(asctime)s :: %(levelname)s :: %(message)s')
+ error_handler = logging.FileHandler((globs.CNIRFolder + '\\error.log'), mode='w', encoding='utf-8', delay=True)
+ info_handler = logging.FileHandler((globs.CNIRFolder + '\\launcher.log'), mode='w', encoding='utf-8')
+
+ error_handler.setLevel(logging.ERROR)
+ error_handler.setFormatter(formatter)
+ logger.addHandler(error_handler)
+
+ info_handler.setLevel(logging.DEBUG)
+ info_handler.setFormatter(formatter)
+ logger.addHandler(info_handler)
+
+ self.logger = logger
+ self.printerr = logger.error
+ self.printdbg = logger.info
\ No newline at end of file