Пример #1
0
    def update(self):
        """"""
        self.switchFileAccount(self.conf.profile)
        try:
            if self.idx != None :
                if not isinstance(self.idx,bytes):
                    self.idx = Io.bytes(self.idx)                
                self.delids.append(self.idx)
        except Exception as e :
            Sys.dprint('error : ')
            Sys.dprint(e)   

        self.index.fixDuplicateIds()
        #~ self.index.fixAccount('gmail5')
        self.index.encrypt()
        msgIndex    = self.mb.buildIndex(self.pathIdx)
        _, self.idx = self.ih.send(msgIndex.as_string(), self.rootBox)
        date        = self.ih.headerField(self.idx, 'date', True)
        self.conf.sets((['uid'  , self.idx              , 'index'],
                       ['date' , date                   , 'index'],
                       ['time' , str(Sys.datetime.now()), 'index']))
        
        Sys.pwlog([(' Index updated ('  , Const.CLZ_0),
                   (str(int(self.idx))  , Const.CLZ_2),
                   (') '                , Const.CLZ_0),
                   (str(date)           , Const.CLZ_7, True)])
        
        try :
            self.ih.delete(self.delids, True)       
        except :
            Sys.dprint('error : ')
            Sys.dprint(e)
        self.ih.clearTrash()
        return True
Пример #2
0
 def build(self):
     Sys.pwlog([(' Reading index, please wait...', Const.CLZ_7, True)])
     self.index = ImpraIndex(self.conf.get('key','keys'), self.pathIdx, self.getIndexDefaultCatg(), self.getAccountList())
     defUsers   = self.conf.get('users','catg')
     if not ImpraIndex.SEP_KEY_INTERN+'users' in self.index.dic:
         self.index.dic[ImpraIndex.SEP_KEY_INTERN+'users'] = {}
     for k in self.index.dic[ImpraIndex.SEP_KEY_INTERN+'users']:
         if self.index.dic[ImpraIndex.SEP_KEY_INTERN+'users'][k] not in [ i.strip() for i in defUsers.split(',')]:
             self.conf.set('users',defUsers+', '+self.index.dic[ImpraIndex.SEP_KEY_INTERN+'users'][k],'catg')
Пример #3
0
    def buildFile(self, fromPath, label="", catg=""):
        count = self.getCountParts(fromPath)
        Sys.pwlog([(" Get Hash... ", Const.CLZ_7, True)])
        sha256 = hash_sha256_file(fromPath)
        Sys.pwlog([(" hash : ", Const.CLZ_0), (sha256, Const.CLZ_2, True), (" Build File...", Const.CLZ_0, True)])

        kg = KeyGen(128)
        size = Sys.getsize(fromPath)
        row = self.idxu.index.get(sha256)
        if row is None:
            if label == "":
                label, ext = Sys.getFileExt(Sys.basename(fromPath))
            else:
                label, ext = Sys.getFileExt(label)
            if catg == "":
                catg = self.idxu.index.getAutoCatg(ext)
            size = Sys.getsize(fromPath)

            Sys.pwlog(
                [
                    (" Splitting ", Const.CLZ_1),
                    (label, Const.CLZ_7),
                    (ext, Const.CLZ_7),
                    (" (", Const.CLZ_0),
                    (Sys.readableBytes(size), Const.CLZ_3),
                    (")", Const.CLZ_0, True),
                ]
            )
            Sys.cli_emit_progress(0)
            Sys.sleep(0.2)
            km = Kirmah(kg.key)
            km.DIR_OUTBOX = self.outbox
            # hlst genetate with sha256
            hlst = km.ck.getHashList(sha256, int(count), True)
            usr = self.idxu.conf.get("name", "infos")
            ownerHash = self.idxu.mb.getHashName(usr)
            km.split(fromPath, hlst)
            Sys.pwlog([(" done ", Const.CLZ_2, True)])
            row = [kg.key, label, ext, count, catg, hlst, usr, ownerHash, sha256, size]
            self.backupAddMap(row)

        else:

            Sys.pwlog(
                [
                    (" File Already exist ! ", Const.CLZ_1, True),
                    (" id : ".rjust(10, " "), Const.CLZ_0),
                    (str(row[ImpraIndex.UID]), Const.CLZ_1, True),
                    (" label : ".rjust(10, " "), Const.CLZ_0),
                    (row[ImpraIndex.LABEL], Const.CLZ_3, True),
                ]
            )

            row = None
        return row
Пример #4
0
 def encrypt(self, fromPath=None):
     """"""
     if fromPath is None :
         fromPath = self.pathPlain
     Sys.pwlog([(' Encrypt Index... ' , Const.CLZ_0, True)])
     Io.set_data(fromPath, jdumps(self.dic))        
     call = ' '.join([Sys.executable, 'kirmah-cli.py', 'enc', '-qfj2' if Sys.isUnix() else '-qf', fromPath, '-z', '-r', '-m', '-o', fromPath+Kirmah.EXT, '-k', self.keyPath ])
     #~ print(call)
     Sys.sysCall(call)
     Io.removeFile(fromPath)
     Sys.pwlog([(' done', Const.CLZ_2, True)])   
     return Io.get_data(fromPath+Kirmah.EXT, True)
Пример #5
0
 def clearTrash(self):
     """"""
     self.cnx.select(self.BOXS[self.TRASH])
     ids = self.search('ALL',True)
     if len(ids) > 0 and ids[0]!='' and ids[0]!=None:
         delids = ImapHelper._getIdsList(ids)            
         status, resp = self.cnx.uid('store', delids, self.FLAGS, self.DELETED )
         
         Sys.pwlog([(' Deleting msg ', Const.CLZ_0),
                    (delids                    , Const.CLZ_1),
                    (' '+status              , Const.CLZ_7, True)])
         self.cnx.expunge()
     self.cnx.select(self.rootBox)
Пример #6
0
 def removeFile(self, uid):
     """"""
     # ~ Sys.pwlog([(Const.LINE_SEP_CHAR*Const.LINE_SEP_LEN , Const.CLZ_0, True)])
     done = False
     key = self.idxu.index.getById(uid)
     row = self.idxu.index.get(key)
     if row is not None:
         account = self.idxu.switchFileAccount(row[self.idxu.index.ACCOUNT])
         Sys.pwlog([(" Removing... plz wait. ", Const.CLZ_7)])
         km = Kirmah(row[self.idxu.index.KEY])
         hlst = km.ck.getHashList(key, row[self.idxu.index.PARTS], True)
         ids = self.idxu.ih.searchBySubject(hlst["head"][2], True)
         self.idxu.ih.delete(ids, True, True)
         self.idxu.ih.clearTrash()
         self.idxu.switchFileAccount(self.idxu.conf.profile)
         self.idxu.get(True)
         self.idxu.index.rem(key)
         done = self.idxu.update()
     return done, key
Пример #7
0
 def decrypt(self, fromPath=None):
     """"""        
     done = False
     try :
         if fromPath is None :
             fromPath = self.path
         toPath = fromPath[:-len(Kirmah.EXT)] if fromPath.endswith(Kirmah.EXT) else fromPath+'.dump'
         if Io.file_exists(fromPath) :
             Sys.pwlog([(' Decrypt Index... '                        , Const.CLZ_0, True)])
             call = ' '.join([Sys.executable, 'kirmah-cli.py', 'dec', '-qfj2' if Sys.isUnix() else '-qf', fromPath, '-z', '-r', '-m', '-o', toPath, '-k', self.keyPath ])
             print(call)
             Sys.sysCall(call)
             data   = jloads(Io.get_data(toPath))
             Io.removeFile(toPath)
         else :
             data = {}
         done = True
     except ValueError as e:
         raise BadKeyException(e)
     Sys.pwlog([(' done'if done else ' ko'    , Const.CLZ_2 if done else Const.CLZ_1, True)])
     return data
Пример #8
0
    def editFile(self, key, label, category):
        """"""
        # ~ Sys.pwlog([(Const.LINE_SEP_CHAR*Const.LINE_SEP_LEN , Const.CLZ_0, True)])
        done = False
        uid = self.idxu._getId(True)
        uidx = self.idxu.conf.get("uid", "index")
        if int(uid) != int(uidx):
            self.idxu.get(True)
        row = self.idxu.index.get(key)
        if row is not None:
            if row[ImpraIndex.LABEL] != label or row[ImpraIndex.CATG] != category:

                Sys.pwlog(
                    [
                        (" Editing file ", Const.CLZ_0),
                        (row[ImpraIndex.LABEL], Const.CLZ_7),
                        (" [", Const.CLZ_0),
                        (row[ImpraIndex.CATG], Const.CLZ_4),
                        ("] to : ", Const.CLZ_0),
                        (label if label is not None else row[ImpraIndex.LABEL], Const.CLZ_3),
                        (" [", Const.CLZ_0),
                        (category if category is not None else row[ImpraIndex.CATG], Const.CLZ_2),
                        ("]", Const.CLZ_0, True),
                    ]
                )

                done = self.idxu.index.edit(key, label, category)

        Sys.pwlog([(" done" if done else "ko", Const.CLZ_2 if done else Const.CLZ_1, True)])
        if done:
            Sys.pwlog([(" Updating index...", Const.CLZ_0, True)])
            self.idxu.update()
        return done
Пример #9
0
    def switchAccount(self, conf, box='INBOX', force=False):
        """"""
        if force or self.cnx is None or self.cnxusr is not conf.user :
            try :
                Sys.pwlog([(' Attempt to login... '                , Const.CLZ_7),
                           ('('                                    , Const.CLZ_0),
                           (conf.user                              , Const.CLZ_2),
                           ('@'                                    , Const.CLZ_0),
                           (conf.host                              , Const.CLZ_3),
                           (':'                                    , Const.CLZ_0),
                           (conf.port                              , Const.CLZ_4),
                           (')'                                    , Const.CLZ_0, True)])

                self.cnx = ImapClient(conf.host,conf.port)
            except Exception as e :
                raise BadHostException()

            try :
                status, resp = self.cnx.login(conf.user,conf.pwd)

            except Exception as e :
                status = self.KO
                pass
            finally :
                if status == self.KO :
                    self.cnxusr = None
                    raise BadLoginException(' Cannot login with '+conf.user+':'+conf.pwd)
                else :
                    Sys.pwlog([(' Connected ', Const.CLZ_2, True),
                               (Const.LINE_SEP_CHAR*Const.LINE_SEP_LEN , Const.CLZ_0, True)])
                    self.cnxusr = conf.user
                    try :
                        status, resp = self.cnx.select(self.rootBox)
                        if status == self.KO and not self.noBoxCreat:
                            self.createBox(self.rootBox)
                            status, resp = self.cnx.select(self.rootBox)
                        self.initBoxNames()
                    except Exception as e :
                        print(e)
Пример #10
0
    def getFileParts(self, row, ids):
        """"""
        done = False
        if len(ids) >= row[self.idxu.index.PARTS]:
            for i, uid in enumerate(ids):
                d = Sys.datetime.now()
                self.idxu.ih.getAttachment(uid, self.inbox, True)

                Sys.pwlog(
                    [
                        (" part ", Const.CLZ_0),
                        (str(i + 1).rjust(2, " "), Const.CLZ_2),
                        (" / ", Const.CLZ_0),
                        (str(len(ids)), Const.CLZ_3),
                        (" downloaded in ", Const.CLZ_0),
                        (Sys.getDelta(d), Const.CLZ_4, True),
                    ]
                )

                Sys.cli_emit_progress(int((i + 1) * 100 / len(ids)))
                Sys.sleep(0.5)

            Sys.mkdir_p(self.deploy + row[self.idxu.index.CATG])
            Sys.cli_emit_progress(100)
Пример #11
0
    def getInfo(self, uid):
        """"""
        done = False
        key = self.idxu.index.getById(uid)
        row = self.idxu.index.get(key)
        if row is not None:
            account = self.idxu.switchFileAccount(row[self.idxu.index.ACCOUNT])
            km = Kirmah(row[self.idxu.index.KEY])
            hlst = km.ck.getHashList(key, row[self.idxu.index.PARTS], True)

            Sys.pwlog(
                [
                    ("id ".rjust(14, " ") + ": ", Const.CLZ_0),
                    (str(row[ImpraIndex.UID]), Const.CLZ_1, True),
                    ("hash ".rjust(14, " ") + ": ", Const.CLZ_0),
                    (row[ImpraIndex.HASH], Const.CLZ_2, True),
                    ("name ".rjust(14, " ") + ": ", Const.CLZ_0),
                    (row[ImpraIndex.LABEL] + row[ImpraIndex.EXT], Const.CLZ_7, True),
                    ("size ".rjust(14, " ") + ": ", Const.CLZ_0),
                    (Sys.readableBytes(row[ImpraIndex.SIZE]), Const.CLZ_6, True),
                    ("category ".rjust(14, " ") + ": ", Const.CLZ_0),
                    (row[ImpraIndex.CATG], Const.CLZ_5, True),
                    ("user ".rjust(14, " ") + ": ", Const.CLZ_0),
                    (self.idxu.index.getUser(row[ImpraIndex.USER]), Const.CLZ_3),
                    (" (" + row[ImpraIndex.USER] + ")", Const.CLZ_5, True),
                    ("account ".rjust(14, " ") + ": ", Const.CLZ_0),
                    (self.idxu.conf.get("user", "imap", row[ImpraIndex.ACCOUNT]), Const.CLZ_4, True),
                    (Const.LINE_SEP_CHAR * Const.LINE_SEP_LEN, Const.CLZ_0, True),
                    ("subject ".rjust(14, " ") + ": ", Const.CLZ_0),
                    (hlst["head"][2], Const.CLZ_1, True),
                ]
            )

            ids = self.idxu.ih.searchBySubject(hlst["head"][2], True)

            for i, uid in enumerate(ids):
                if i < len(hlst["data"]):

                    Sys.pwlog(
                        [
                            ("attach file ".rjust(14, " ") + ": ", Const.CLZ_0),
                            (hlst["data"][i][1] + Kirmah.EXT, Const.CLZ_2),
                            (" (", Const.CLZ_0),
                            (str(int(uid)), Const.CLZ_1),
                            (") (", Const.CLZ_0),
                            (str(hlst["data"][i][4]), Const.CLZ_3),
                            (")", Const.CLZ_0, True),
                        ]
                    )
                else:
                    Sys.pwlog(
                        [(" Wrong id (to del)".ljust(14, " ") + ": ", Const.CLZ_2), (str(uid), Const.CLZ_2, True)]
                    )
        return done
Пример #12
0
 def get(self, forceRefresh=False):
     """"""
     self.switchFileAccount(self.conf.profile)
     index   = None
     uid     = self.conf.get('uid'  ,'index')
     date    = self.conf.get('date' ,'index')
     tstamp  = self.conf.get('time' ,'index')
     refresh = forceRefresh        
     delta   = None if tstamp is None else Sys.datetime.now() - Sys.datetime.strptime(tstamp[:-7], '%Y-%m-%d %H:%M:%S')
     if not refresh and tstamp is not None and delta < Sys.timedelta(minutes = 3) :
         # getFromFile            
         if uid != None and Io.file_exists(self.pathIdx): # int(self.idx) == int(uid) 
             self.idx = uid
             Sys.pwlog([(' Get index from cache '  , Const.CLZ_7),
                        ('('                       , Const.CLZ_0),
                        (str(int(self.idx))        , Const.CLZ_2),
                        (')'                       , Const.CLZ_0, True)])
         else: refresh = True
     else: refresh = True
     self.irefresh = refresh
     if refresh :
         Sys.pwlog([(' Checking index...', Const.CLZ_0, True)])
         self._getId()
         if self.idx :
             if int(self.idx) != int(uid) or not Io.file_exists(self.pathIdx):
                 Sys.pwlog([(' Refreshing index (local:', Const.CLZ_0),
                            (str(int(uid))              , Const.CLZ_2),
                            (' / remote:'               , Const.CLZ_0),
                            (str(int(self.idx))         , Const.CLZ_1),
                            (')'                        , Const.CLZ_0, True)])
                 
                 date = self.ih.headerField(self.idx, 'date', True)
                 self.conf.sets((['uid'  , str(int(self.idx))     , 'index'],
                                 ['date' , date                   , 'index'],
                                 ['time' , str(Sys.datetime.now()), 'index']))
                 self._saveLocalIndex()
             else :
                 Sys.pwlog([(' Get index from cache '  , Const.CLZ_7),
                            ('('                       , Const.CLZ_0),
                            (str(int(self.idx))        , Const.CLZ_2),
                            (')'                       , Const.CLZ_0, True)])
             self.conf.set('time',str(Sys.datetime.now()),'index')
     self.build()        
Пример #13
0
    def run(self):
        """"""
        self.cancelled = False
        self.evtStop.clear()
        Sys.g.THREAD_CLI       = self
        Sys.g.GUI              = True
        Sys.g.GUI_PRINT_STDOUT = True
        done                   = False
        self.can_retry         = True
        init(conf.PRG_NAME, Sys.g.DEBUG, loglvl=Const.LOG_APP)        
        try :
            if self.impst is None :
                
                label = ' [[ INIT IMPRASTORAGE ]] '
                label = ' '+'~'*((Const.LINE_SEP_LEN-len(label))//2-1)+label+'~'*((Const.LINE_SEP_LEN-len(label))//2-1)+' '
                Sys.pwlog([(Const.LINE_SEP_CHAR*Const.LINE_SEP_LEN , Const.CLZ_0     , True),
                           (label.ljust(Const.LINE_SEP_LEN, ' ')   , Const.CLZ_INIT  , True),
                           (Const.LINE_SEP_CHAR*Const.LINE_SEP_LEN , Const.CLZ_0     , True)])
                
                self.impst = ImpraStorage(self.conf, wkdir='.'+Sys.sep+'wk'+Sys.sep)

            done = True
        except Exception as e :
            self.emit('needconfig')
            raise e
        self.emit('indexrefreshed', done)
        if done :        
            while not self.evtStop.is_set() or not self.cancelled:
                with self.condition :
                    self.condition.wait_for(lambda : not self.taskQueue.empty(), 2)
                    
                    if self.can_retry and self.impst.hasBackupAddMap():
                        self.emit('hasaddretry')
                        self.can_retry = False
                    
                    if not self.taskQueue.empty():
                        task, params, idtask = self.taskQueue.get_nowait()
                        label = ' [[ TASK '+str(idtask)+' : '+self.TASK_LABEL[task].upper()+' ]] '
                        label = ' '+'>'*((Const.LINE_SEP_LEN-len(label))//2-1)+label+'<'*((Const.LINE_SEP_LEN-len(label))//2-1)+' '
                        Sys.pwlog([(Const.LINE_SEP_CHAR*Const.LINE_SEP_LEN , Const.CLZ_0     , True),
                                   (label.ljust(Const.LINE_SEP_LEN, ' ')   , Const.CLZ_ACTION, True),
                                   (Const.LINE_SEP_CHAR*Const.LINE_SEP_LEN , Const.CLZ_0     , True)])
                        
                        try:
                            if task is self.TASK_WAIT :
                                print('wait')
                                Sys.sleep(params)
                            elif task is self.TASK_GET:
                                #~ mg        = Manager(self.taskGet, 1, None, Sys.g.MPEVENT, uid=params)
                                #~ mg.run()
                                #~ self.emit('fileget', True, '')
                                #~ Thread(target=self.taskGet, name='impra-1', kwargs={'uid':params}).start()
                                print(params)
                                self.taskGet(params)
                            elif task is self.TASK_ADD:
                                self.taskAdd(params)
                            elif task is self.TASK_ADD_RETRY:
                                self.taskAddRetry(params)
                            elif task is self.TASK_REFRESH:
                                self.taskRefresh(params)
                            elif task is self.TASK_INFOS:
                                self.taskInfos(params)
                            elif task is self.TASK_REMOVE:
                                self.taskRemove(params)
                            elif task is self.TASK_EDIT:
                                self.taskEdit(params)
                            self.taskQueue.task_done()

                        except self.impst.SocketError() as e :
                            Sys.pwarn((('ImpraThread.run : ',(str(e),Sys.CLZ_WARN_PARAM), ' !'),))
                            self.impst.reconnect()

                        except Exception as e:
                            print(type(e))
                            Sys.pwarn((('ImpraThread.run : ',(str(e),Sys.CLZ_WARN_PARAM), ' !'),))                            
                    else :
                        """"""
                Sys.sleep(0.5)
        self.emit('completed')
Пример #14
0
 def reconnect(self):
     """"""
     Sys.pwlog([(' Reconnecting... ', Const.CLZ_7, True)])
     self.switchAccount(self.conf, self.rootBox, True)
Пример #15
0
    def getFile(self, uid):
        """"""
        # ~ Sys.pwlog([(Const.LINE_SEP_CHAR*Const.LINE_SEP_LEN , Const.CLZ_0, True)])
        done = False
        key = self.idxu.index.getById(uid)
        row = self.idxu.index.get(key)
        filePath = None
        try:
            if row is not None:
                account = self.idxu.switchFileAccount(row[self.idxu.index.ACCOUNT])
                km = Kirmah(row[self.idxu.index.KEY])
                hlst = km.ck.getHashList(key, row[self.idxu.index.PARTS], True)
                ids = self.idxu.ih.searchBySubject(hlst["head"][2], True)
                Sys.cli_emit_progress(0)
                Sys.sleep(0.2)
                Sys.pwlog(
                    [
                        (" Downloading : ", Const.CLZ_7),
                        (row[self.idxu.index.LABEL] + row[self.idxu.index.EXT], Const.CLZ_2),
                        (" (", Const.CLZ_0),
                        (Sys.readableBytes(row[self.idxu.index.SIZE]), Const.CLZ_3),
                        (")", Const.CLZ_0),
                        (" please wait...", Const.CLZ_7, True),
                    ]
                )

                if len(ids) >= row[self.idxu.index.PARTS]:
                    self.getFileParts(row, ids)

                    Sys.pwlog([(" Merging parts...", Const.CLZ_7, True)])
                    Sys.cli_emit_progress(0)
                    Sys.sleep(0.2)
                    filePath = km.merge(
                        hlst,
                        self.deploy + row[self.idxu.index.CATG] + Sys.sep + row[self.idxu.index.LABEL],
                        ext=row[self.idxu.index.EXT],
                        uid=row[self.idxu.index.UID],
                        dirs=self.inbox,
                    )

                    Sys.pwlog(
                        [
                            (" Deployed as ", Const.CLZ_7),
                            (filePath, Const.CLZ_2),
                            (" (", Const.CLZ_0),
                            (Sys.readableBytes(Sys.getsize(filePath)), Const.CLZ_3),
                            (") ", Const.CLZ_0, True),
                            (" Checking integrity...", Const.CLZ_7, True),
                        ]
                    )
                    Sys.sleep(0.2)
                    sha256 = hash_sha256_file(filePath)
                    done = sha256 == row[ImpraIndex.HASH]
                    done = True

                else:
                    print("incomplete")

        except Exception as e:
            print(e)
        Sys.pwlog([(" done" if done else "ko", Const.CLZ_2 if done else Const.CLZ_1, True)])
        return done, filePath
Пример #16
0
    def sendFile(self, data, retry=False):
        """"""
        done = None
        key = None
        if data is not None:
            key, label, ext, count, catg, hlst, usr, ownerHash, sha256, size = data
            self.idxu.index.addUser(usr, ownerHash)
            account = self.idxu.switchFileAccount()
            sendIds = []
            cancel = False
            d = None

            Sys.cli_emit_progress(0)
            Sys.sleep(0.2)
            if not retry:
                Sys.pwlog(
                    [
                        (" Sending... ", Const.CLZ_7),
                        (" (", Const.CLZ_0),
                        (
                            " ~" + Sys.readableBytes(Sys.getsize(self.outbox + hlst["data"][0][1] + Kirmah.EXT)),
                            Const.CLZ_3,
                        ),
                        (" per msg ) ", Const.CLZ_0, True),
                    ]
                )
            else:
                Sys.pwlog(
                    [
                        (" Retry sending last file... ", Const.CLZ_0),
                        (label + ext, Const.CLZ_7),
                        (" (" + catg + ")", Const.CLZ_3, True),
                    ]
                )

            ignore = False

            for i, row in enumerate(hlst["data"]):
                """"""
                if retry:
                    if not Io.file_exists(self.outbox + row[1] + Kirmah.EXT):
                        continue
                    elif not ignore:
                        Sys.pwlog([(" Ignoring file 1 to " + str(i), Const.CLZ_1, True)])
                        ignore = True

                d = Sys.datetime.now()
                msg = self.idxu.mb.build(usr, "all", hlst["head"][2], self.outbox + row[1] + Kirmah.EXT)
                try:
                    mid = self.idxu.ih.send(msg.as_string(), self.rootBox)
                except Exception as e:
                    Sys.pwarn((("addFile : ", (str(e), Sys.CLZ_WARN_PARAM), " !"),))
                    Sys.echo("waiting 5 s and retry")
                    Sys.sleep(5)
                    # force reconnect
                    self.impst.idxu.switchFileAccount(account, True)
                    # retry
                    mid = self.idxu.ih.send(msg.as_string(), self.rootBox)
                finally:
                    if not mid is None:
                        status, resp = self.idxu.ih.fetch(mid[1], "(UID BODYSTRUCTURE)", True)
                        if status == self.idxu.ih.OK:
                            sendIds.append((mid[1], row))
                            Sys.pwlog(
                                [
                                    (" part ", Const.CLZ_0),
                                    (str(row[0]).rjust(2, "0"), Const.CLZ_2),
                                    (" sent as msg ", Const.CLZ_0),
                                    (str(mid[1]).rjust(5, "0"), Const.CLZ_1),
                                    (" (", Const.CLZ_7),
                                    (str(int(row[4]) + 1).rjust(2, "0"), Const.CLZ_2),
                                    ("/", Const.CLZ_7),
                                    (str(count), Const.CLZ_3),
                                    (") in ", Const.CLZ_7),
                                    (Sys.getDelta(d), Const.CLZ_4, True),
                                ]
                            )

                            Sys.cli_emit_progress(int((i + 1) * 100 / len(hlst["data"])))

                            Sys.removeFile(self.outbox + row[1] + Kirmah.EXT)
                        else:
                            Sys.pwarn((("error occured when sending part ", (row[0], Sys.Clz.fgb3), " !"),))

            diff = self.checkSendIds(sendIds, hlst["head"][2])
            if len(sendIds) == count or retry:
                self.idxu.get(True)
                self.idxu.index.add(key, label, hlst["head"][1], ext, ownerHash, catg, sha256, size, account)
                done = self.idxu.update()
                Io.removeFile(self.addmapPath + Kirmah.EXT)

            # resending missing parts
            else:
                Sys.pwarn((("TODO => must resending ", ("missing", Sys.CLZ_WARN_PARAM), " parts"),))
                print(diff)

            # clean
            for mid, row in sendIds:
                if Io.file_exists(self.outbox + row[1] + Kirmah.EXT):
                    Sys.removeFile(self.outbox + row[1] + Kirmah.EXT)
            if cancel:
                delids = [mid for mid, row in senids]
                print(delids)
                self.idxu.ih.delete(delids, True)
        return done, key