Code:
#!/usr/bin/python
# Copyright (C) 2007 Rasmus Larsson
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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.
#
# Read the full license agreement here: http://www.gnu.org/licenses/gpl.txt
import os, sys, getopt, bz2, fnmatch
from xml.dom import minidom
DEFSEARCHSTRS = ['Descript.ion','thumbs.db','*.html','*.htm','*.msg','*.permissions','*.pls','*.status','*.url','*.filled','*.debug','*.ccd','*.ioFTPD*','*.banana','*.bad','*.checked','*.raidenftpd.acl','*.SimSfvChk.log','*.message','*.upChk.log','*.crc','imdb.nfo','*.bc!','*(1).nfo','*(2).nfo','*(3).nfo','*.log','*.pls','*.dctmp','*(1).sfv','*.ini','*.bak','*(2).sfv','*.dt!','*.bat','*.ink','*missing','*.antifrag']
#DEFSEARCHSTRS= ['*.srt','*.sub','*.idx'] #removed
DEFSOURCE="bz2"
DCCONFFILE='~/.dc++/DCPlusPlus.xml'
DCSHAREFILE='~/.dc++/files.xml.bz2'
class DCFileHandler:
""" Opens the DC++ config file and share list file. """
def __init__(self, configfile='~/.dc++/DCPlusPlus.xml', sharelistfile='~/.dc++/files.xml.bz2'):
"""
configfile -- location and name of configfile relative to the userdirectory, default is ~/.dc++/DCPlusPlus.xml
sharelistfile -- location and name of the sharelistfile relative to the userdirectory, default is ~/.dc++/files.xml.bz2
"""
self.xmldirlist = self.extractShareDirectories(configfile)
self.xmlsharelist = self.extractSharelist(sharelistfile)
def expandUserDir(self, string):
if(string[0]=='~'): return os.path.expanduser(string)
else: return string
def extractShareDirectories(self, configfile):
"""Extract the share directories from DCPlusPlus.xml"""
try:
fsock_conf = file(self.expandUserDir(configfile))
xmldoc = minidom.parse(fsock_conf)
fsock_conf.close()
return xmldoc
except IOError:
print IOError
sys.exit(2)
def extractSharelist(self, sharelistfile):
try:
fsock_share = bz2.BZ2File(self.expandUserDir(sharelistfile))
xmlsharelist = minidom.parse(fsock_share)
fsock_share.close()
return xmlsharelist
except IOError:
print IOError
sys.exit(2)
class DCAnalyzer:
def __init__(self, dcfh):
self.dcfilehandler = dcfh
self.createDirMap()
def lookupShareDirPath(self, dirname):
"""Lookup the complete path (dir included) of a directory."""
return self.dirmap[dirname]
def createDirMap(self):
sharedirlist = self.dcfilehandler.xmldirlist.getElementsByTagName('Share') #parametrize?
firstref = sharedirlist[0]
dirlist = firstref.getElementsByTagName('Directory') #parametrize?
self.dirmap = {}
for dir in dirlist:
self.dirmap[ dir.attributes['Virtual'].value ] = dir.firstChild.data
def search(self, searchstrings, source="bz2"):
"""
searchstrings -- list of search strings to look for
source -- where to look for the files, in the share list ("bz2", default) or in the file system ("fs")
"""
if(source == "bz2"):
return self.searchbz2(searchstrings)
elif(source == "fs"):
return self.searchfs(searchstrings)
else:
raise Error, source + " is an unknown source"
def searchfs(self, searchstrings):
""" Search the share directories (using unix 'find') for files matchin search strings.
searchstrings -- list of search strings
"""
print "Searching filesystem...\n\n"
print 'Search strings are: '
print searchstrings
print 'Share directories are:'
for key in self.dirmap:
#print var.firstChild.data
print self.dirmap[key]
print "\n"
files=[]
for key in self.dirmap:
for str in searchstrings:
cmd = 'find ' + self.dirmap[key] + ' -name \'' + str + '\' -print'
o = os.popen(cmd)
foo = o.read()
if ( len(foo) > 0 ):
files.append(foo)
return files
def searchbz2(self, searchstrings):
print "Searching sharelist...\n\n"
files=[]
foundElements=[]
filelist = self.dcfilehandler.xmlsharelist.getElementsByTagName('File') #parametrize?
for elementFile in filelist:
for pattern in searchstrings:
filename = elementFile.attributes['Name'].value
if (fnmatch.fnmatch(filename,pattern)):
foundElements.append(elementFile)
for element in foundElements:
pnames=[]
parents = self.recurseParents(element.parentNode, 'Directory') #parametrize?
for pelement in parents:
pnames.append(pelement.attributes['Name'].value)
path = self.lookupShareDirPath(pnames.pop(0))
for pname in pnames:
path += pname + "/"
path += element.attributes['Name'].value
files.append( path )
return files
def recurseParents(self, parent, name):
"""Recurses the parent and all its parents having 'name' and returns a list of them."""
list=[]
if (parent.parentNode is not None
and parent.parentNode.nodeName == name):
list.extend(self.recurseParents(parent.parentNode, name))
list.append(parent)
return list
def getArgs():
"""Gets the input arguments if there are any."""
myArgs={}
searchstrings = []
configfile=None
sharelistfile=None
source=None
try:
opts, args = getopt.getopt(sys.argv[1:], "he:f:s:", ["help","pattern=","configfile=","sharelistfile="])
except getopt.GetoptError:
usage()
exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit(2)
elif opt in ("-e", "--pattern"):
searchstrings.append(arg)
elif opt in ("-c", "--configfile"):
configfile=arg
elif opt in ("-f","--sharelistfile"):
sharelistfile=arg
elif opt in ("-s","--source"):
source=arg
if(len(searchstrings) == 0):
searchstrings = None
myArgs["sharelistfile"]=sharelistfile
myArgs["configfile"]=configfile
myArgs["searchstrings"]=searchstrings
myArgs["source"]=source
return myArgs
def usage():
"""Prints the correct usage of the program"""
print "This program searches your linuxdc++ share for files with specified search pattern.\
\nIt may work on windows as well, but I haven't tried."
print "Usage:\tsharecheck.py [-h|-e PATTERN*|-c FILEPATH|-f FILEPATH|-s SOURCE] -e\n\t-h, --help shows this help \
\n\t-e, --pattern=[PATTERN] use PATTERN as search expression \
\n\t-c, --configfile=[FILEPATH] use FILEPATH file as DC++ config file, default is ~/.dc++/DCPlusPlus.xml \
\n\t-f, --sharelist=[FILEPATH] use FILEPATH file as DC++ sharelist file, default is ~/.dc++/files.xml.bz2 \
\n\t-s, --source=[SOURCE] look in SOURCE ('bz2'|'fs') (sharelist or filesystem) for files, default is bz2\
\n\nNotes: \
\n\t- Search is performed using fnmatch syntax. 'man fnmatch' for details.\
\n\t- more than one search pattern is permitted.\
\n\nExample: \
\n\t./sharecheck.py -e imdb.* -e Thumbs* -s fs\n\n "
def run():
myArgs = getArgs()
searchstrings = DEFSEARCHSTRS
configfile = DCCONFFILE
sharelistfile = DCSHAREFILE
source = DEFSOURCE
if(myArgs["searchstrings"] is not None):
searchstrings = myArgs["searchstrings"]
if(myArgs["configfile"] is not None):
configfile = myArgs["configfile"]
if(myArgs["sharelistfile"] is not None):
sharelistfile = myArgs["sharelistfile"]
if(myArgs["source"] is not None):
source = myArgs["source"]
dcfh = DCFileHandler(configfile, sharelistfile)
dca = DCAnalyzer(dcfh)
list = dca.search(searchstrings, source)
for l in list:
print l
run()
Bookmarks