1
1
# OneDriveExplorer
2
- # Copyright (C) 2022
2
+ # Copyright (C) 2024
3
3
#
4
4
# This file is part of OneDriveExplorer
5
5
#
29
29
import re
30
30
import base64
31
31
import json
32
+ import psutil
32
33
import ctypes
33
34
import webbrowser
34
35
import argparse
103
104
)
104
105
105
106
__author__ = "Brian Maloney"
106
- __version__ = "2024.11.12 "
107
+ __version__ = "2024.11.20 "
107
108
108
109
rbin = []
109
110
user_logs = {}
123
124
dfs_to_concat = []
124
125
folder_type = []
125
126
dragging_sash = False
127
+ sync_message = None
126
128
df_GraphMetadata_Records = pd .DataFrame (columns = ['fileName' , 'resourceID' , 'graphMetadataJSON' , 'spoCompositeID' ,
127
129
'createdBy' , 'modifiedBy' , 'filePolicies' , 'fileExtension' , 'lastWriteCount' ])
128
130
@@ -232,23 +234,32 @@ def create_widgets(self):
232
234
self .win .bind ('<Configure>' , self .sync_windows )
233
235
234
236
def btn1 (self ):
237
+ parent = psutil .Process (os .getpid ())
238
+ for child in parent .children (recursive = True ):
239
+ child .kill ()
240
+ self .win .destroy ()
235
241
sys .exit ()
236
242
237
243
def btn2 (self ):
238
244
self .root .unbind ("<Configure>" )
245
+ if sync_message :
246
+ sync_message .bind_events ()
239
247
self .win .destroy ()
240
248
241
249
def __callback (self ):
242
250
return
243
251
244
252
def sync_windows (self , event = None ):
245
- x = self .root .winfo_x ()
246
- qw = self .win .winfo_width ()
247
- y = self .root .winfo_y ()
248
- qh = self .win .winfo_height ()
249
- w = self .root .winfo_width ()
250
- h = self .root .winfo_height ()
251
- self .win .geometry ("+%d+%d" % (x + w / 2 - qw / 2 , y + h / 2 - qh / 2 ))
253
+ try :
254
+ x = self .root .winfo_x ()
255
+ qw = self .win .winfo_width ()
256
+ y = self .root .winfo_y ()
257
+ qh = self .win .winfo_height ()
258
+ w = self .root .winfo_width ()
259
+ h = self .root .winfo_height ()
260
+ self .win .geometry ("+%d+%d" % (x + w / 2 - qw / 2 , y + h / 2 - qh / 2 ))
261
+ except Exception :
262
+ pass
252
263
253
264
254
265
class Preferences :
@@ -437,7 +448,7 @@ def __init__(self, root, sql=False):
437
448
self .sql = sql
438
449
self .win = tk .Toplevel (self .root )
439
450
self .win .wm_transient (self .root )
440
- self .win .title ("Load User Hive" )
451
+ self .win .title ("Load User Hive - NTUSER.DAT " )
441
452
self .win .iconbitmap (application_path + '/Images/titles/question.ico' )
442
453
self .win .grab_set ()
443
454
self .win .focus_force ()
@@ -456,9 +467,9 @@ def __init__(self, root, sql=False):
456
467
self .inner_frame .grid (row = 0 , column = 0 , padx = 5 , pady = 5 )
457
468
self .button_frame .grid (row = 2 , column = 0 , columnspan = 3 )
458
469
459
- self .label_i = ttk .Label (self .inner_frame , image = question_img )
470
+ self .label_i = ttk .Label (self .inner_frame , image = reg_img )
460
471
self .label = ttk .Label (self .inner_frame ,
461
- text = "User's registry hive allows the mount points of the SyncEngines to be resolved.\n \n Do you want to provide a registry hive?\n " )
472
+ text = "User's registry hive (NTUSER.DAT) allows the mount points of the SyncEngines to be resolved.\n \n Do you want to provide a registry hive?\n " )
462
473
463
474
self .label_l = ttk .Label (self .inner_frame , text = "Note:" )
464
475
@@ -475,7 +486,7 @@ def __init__(self, root, sql=False):
475
486
takefocus = False ,
476
487
command = self .close_hive )
477
488
478
- self .label_i .grid (row = 0 , column = 0 , rowspan = 2 , sticky = 'n' )
489
+ self .label_i .grid (row = 0 , column = 0 , rowspan = 2 , padx = ( 0 , 5 ), sticky = 'n' )
479
490
self .label .grid (row = 0 , column = 1 , columnspan = 2 , pady = (5 , 0 ), sticky = 'w' )
480
491
self .label_l .grid (row = 1 , column = 1 , sticky = 'nw' )
481
492
self .label_r .grid (row = 1 , column = 2 , padx = 5 , sticky = 'w' )
@@ -496,8 +507,8 @@ def close_hive(self):
496
507
def get_hive (self ):
497
508
global reghive
498
509
reghive = filedialog .askopenfilename (initialdir = "/" ,
499
- title = "Open" ,
500
- filetypes = (("Load user hive " ,
510
+ title = "Open User Registry Hive " ,
511
+ filetypes = (("NTUSER.DAT " ,
501
512
"*.dat" ),))
502
513
if reghive :
503
514
self .win .destroy ()
@@ -1320,13 +1331,24 @@ def create_widgets(self):
1320
1331
def bind_events (self ):
1321
1332
self .root .bind ('<Configure>' , self .sync_windows )
1322
1333
self .win .bind ('<Configure>' , self .sync_windows )
1334
+ self .root .bind ("<Map>" , self .bring_window_back )
1335
+
1336
+ def bring_window_back (self , e ):
1337
+ self .win .attributes ('-topmost' , 1 )
1338
+ self .win .attributes ('-topmost' , 0 )
1323
1339
1324
1340
def sync_windows (self , event = None ):
1341
+ on_top = self .root .tk .eval ('wm stackorder ' + str (self .win )+ ' isabove ' + str (self .root ))
1342
+ if on_top == '0' :
1343
+ self .bring_window_back (event )
1344
+
1325
1345
if 'thread_load' in str (threading .enumerate ()) and len (threading .enumerate ()) <= 4 :
1326
1346
self .root .unbind ("<Configure>" )
1347
+ self .root .unbind ("<Map>" )
1327
1348
self .win .destroy ()
1328
1349
if len (threading .enumerate ()) <= 3 :
1329
1350
self .root .unbind ("<Configure>" )
1351
+ self .root .unbind ("<Map>" )
1330
1352
self .win .destroy ()
1331
1353
try :
1332
1354
x = self .root .winfo_x ()
@@ -1341,6 +1363,7 @@ def sync_windows(self, event=None):
1341
1363
1342
1364
def close_sync (self ):
1343
1365
self .root .unbind ("<Configure>" )
1366
+ self .root .unbind ("<Map>" )
1344
1367
self .win .destroy ()
1345
1368
1346
1369
def __callback (self ):
@@ -1596,7 +1619,7 @@ def do_popup(self, event):
1596
1619
popup .add_command (label = "Remove OneDrive Folder" ,
1597
1620
image = self .rof_img ,
1598
1621
compound = 'left' ,
1599
- command = lambda : [ self .thread_del_folder (curItem ), SyncMessage ( root )] )
1622
+ command = lambda : self .thread_del_folder (curItem ))
1600
1623
popup .add_separator ()
1601
1624
1602
1625
if image [0 ] != str (del_img ):
@@ -1689,8 +1712,10 @@ def copy_name(self, values):
1689
1712
self .root .clipboard_append (name_item .split ("Name: " )[1 ])
1690
1713
1691
1714
def thread_del_folder (self , iid ):
1715
+ global sync_message
1692
1716
message .unbind ('<Double-Button-1>' , bind_id )
1693
1717
value_label ['text' ] = ''
1718
+ sync_message = SyncMessage (root )
1694
1719
t1 = threading .Thread (target = self .del_folder , args = (iid ,), daemon = True )
1695
1720
t1 .start ()
1696
1721
root .after (200 , check_if_ready , t1 , "df" )
@@ -3373,6 +3398,7 @@ def fixed_map(option):
3373
3398
3374
3399
3375
3400
def search (item = '' ):
3401
+ root .update ()
3376
3402
query = search_entry .get ()
3377
3403
if len (query ) == 0 :
3378
3404
return
@@ -3447,6 +3473,7 @@ def clear_search():
3447
3473
3448
3474
3449
3475
def delete_item_and_descendants (tree , item = '' ):
3476
+ root .update ()
3450
3477
children = tree .get_children (item )
3451
3478
for child in children :
3452
3479
if child in file_items :
@@ -3748,17 +3775,20 @@ def live_system(menu):
3748
3775
pb .stop ()
3749
3776
odl = parse_odl (logs [0 ], key , pb , value_label , gui = True )
3750
3777
tb = ttk .Frame ()
3751
- pt = pandastablepatch .MyTable (tb ,
3752
- dataframe = odl ,
3753
- maxcellwidth = 900 ,
3754
- showtoolbar = False ,
3755
- showstatusbar = False ,
3756
- enable_menus = True ,
3757
- editable = False )
3758
- tv_frame .add (tb , text = f'{ key } Logs ' )
3759
- pt .adjustColumnWidths ()
3760
- pt .show ()
3761
- user_logs .setdefault (f'{ key } _logs.csv' , pt )
3778
+
3779
+ if not odl .empty :
3780
+ pt = pandastablepatch .MyTable (tb ,
3781
+ dataframe = odl ,
3782
+ maxcellwidth = 900 ,
3783
+ showtoolbar = False ,
3784
+ showstatusbar = False ,
3785
+ enable_menus = True ,
3786
+ editable = False )
3787
+ tv_frame .add (tb , text = f'{ key } Logs ' )
3788
+ pt .adjustColumnWidths ()
3789
+ pt .show ()
3790
+ user_logs .setdefault (f'{ key } _logs.csv' , pt )
3791
+
3762
3792
if menu_data ['odl_save' ] is True :
3763
3793
value_label ['text' ] = f"Saving { key } _logs.csv. Please wait...."
3764
3794
pb .configure (mode = 'indeterminate' )
@@ -3798,7 +3828,7 @@ def open_dat(menu):
3798
3828
global reghive
3799
3829
global recbin
3800
3830
filename = filedialog .askopenfilename (initialdir = "/" ,
3801
- title = "Open" ,
3831
+ title = "Open <UserCid>.dat " ,
3802
3832
filetypes = (("OneDrive dat file" ,
3803
3833
"*.dat *.dat.previous" ),
3804
3834
))
@@ -3896,7 +3926,7 @@ def odl(folder_name, csv=False):
3896
3926
breadcrumb .disable_crumbs ()
3897
3927
file_manager .tv2 .delete (* file_manager .tv2 .get_children ())
3898
3928
file_manager .tv3 .delete (* file_manager .tv3 .get_children ())
3899
- key_find = re .compile (r'Users/(?P<user>.*)? /AppData' )
3929
+ key_find = re .compile (r'Users/(?P<user>[^/]+) /AppData' )
3900
3930
pb .stop ()
3901
3931
start = time .time ()
3902
3932
@@ -3944,7 +3974,7 @@ def odl(folder_name, csv=False):
3944
3974
if len (key ) == 0 :
3945
3975
key = 'ODL'
3946
3976
else :
3947
- key = key [0 ]
3977
+ key = key [- 1 ]
3948
3978
odl = parse_odl (folder_name , key , pb , value_label , gui = True )
3949
3979
3950
3980
tb = ttk .Frame ()
@@ -4473,6 +4503,7 @@ def sync():
4473
4503
4474
4504
def check_if_ready (thread , t_string ):
4475
4505
global cstruct_df
4506
+ global sync_message
4476
4507
if thread .is_alive ():
4477
4508
# not ready yet, run the check again soon
4478
4509
root .after (200 , check_if_ready , thread , t_string )
@@ -4483,6 +4514,7 @@ def check_if_ready(thread, t_string):
4483
4514
if t_string == "s" :
4484
4515
cstruct_df = load_cparser (args .cstructs )
4485
4516
if t_string == "tca" or t_string == "df" :
4517
+ sync_message = None
4486
4518
widgets_normal ()
4487
4519
if t_string == "lp" :
4488
4520
root .event_generate ("<Configure>" )
@@ -4499,7 +4531,9 @@ def thread_search():
4499
4531
4500
4532
4501
4533
def thread_clear_all ():
4534
+ global sync_message
4502
4535
message .unbind ('<Double-Button-1>' , bind_id )
4536
+ sync_message = SyncMessage (root )
4503
4537
t1 = threading .Thread (target = clear_all , daemon = True )
4504
4538
t1 .start ()
4505
4539
root .after (200 , check_if_ready , t1 , "tca" )
@@ -4723,7 +4757,7 @@ def stop_drag(event):
4723
4757
error_img = ImageTk .PhotoImage (Image .open (application_path + '/Images/gui/error.png' )) # ExportResult
4724
4758
asc_img = ImageTk .PhotoImage (Image .open (application_path + '/Images/gui/table_sort_asc.png' )) # pandastable
4725
4759
desc_img = ImageTk .PhotoImage (Image .open (application_path + '/Images/gui/table_sort_desc.png' )) # pandastable
4726
- question_img = ImageTk .PhotoImage (Image .open (application_path + '/Images/gui/question .png' )) # hive
4760
+ reg_img = ImageTk .PhotoImage (Image .open (application_path + '/Images/gui/registry .png' )) # hive
4727
4761
trash_img = ImageTk .PhotoImage (Image .open (application_path + '/Images/gui/trashcan.png' )) # recbin
4728
4762
ode_img = ImageTk .PhotoImage (Image .open (application_path + '/Images/gui/ode.png' )) # about
4729
4763
meta_img = ImageTk .PhotoImage (Image .open (application_path + '/Images/gui/tools.png' )) # about
@@ -5052,7 +5086,7 @@ def stop_drag(event):
5052
5086
odsmenu .add_command (label = "Import CSV" , image = csv_img , compound = 'left' ,
5053
5087
command = lambda : import_csv (odsmenu ))
5054
5088
odsmenu .add_command (label = "Unload all files" , image = uaf_img , compound = 'left' ,
5055
- command = lambda : [ thread_clear_all (), SyncMessage ( root )] , accelerator = "Alt+0" )
5089
+ command = lambda : thread_clear_all (), accelerator = "Alt+0" )
5056
5090
odsmenu .entryconfig ("Unload all files" , state = 'disable' )
5057
5091
5058
5092
odlmenu .add_command (label = "Load ODL logs" , image = folderop_img , compound = 'left' ,
@@ -5070,7 +5104,7 @@ def stop_drag(event):
5070
5104
projmenu .add_command (label = "SaveAs" , image = saveas_img , compound = 'left' ,
5071
5105
command = lambda : saveAs_proj ())
5072
5106
projmenu .add_command (label = "Unload" , image = ual_img , compound = 'left' ,
5073
- command = lambda : [thread_clear_all (), del_logs (), SyncMessage ( root ) ])
5107
+ command = lambda : [thread_clear_all (), del_logs ()])
5074
5108
projmenu .entryconfig ("Save" , state = 'disable' )
5075
5109
root .unbind ('<Alt-s>' )
5076
5110
projmenu .entryconfig ("SaveAs" , state = 'disable' )
0 commit comments