+class Notmuch:
+
+ def __init__(self):
+ self._config = None
+
+ def cmd_usage(self):
+ """Print the usage text and exits"""
+ data={}
+ names = self.get_user_email_addresses()
+ data['fullname'] =names[0] if names[0] else 'My Name'
+ data['mailaddress']=names[1] if names[1] else 'My@email.address'
+ print (Notmuch.USAGE % data)
+
+ def cmd_new(self):
+ """Run 'notmuch new'"""
+ #get the database directory
+ db = Database(mode=Database.MODE.READ_WRITE)
+ path = db.get_path()
+
+ (added, moved, removed) = self._add_new_files_recursively(path, db)
+ print (added, moved, removed)
+
+ def cmd_help(self, subcmd=None):
+ """Print help text for 'notmuch help'"""
+ if len(subcmd) > 1:
+ print "Help for specific commands not implemented"
+ return
+
+ print (Notmuch.HELPTEXT)
+
+ def _get_user_notmuch_config(self):
+ """Returns the ConfigParser of the user's notmuch-config"""
+ # return the cached config parser if we read it already
+ if self._config is not None:
+ return self._config
+
+ from ConfigParser import SafeConfigParser
+ config = SafeConfigParser()
+ conf_f = os.getenv('NOTMUCH_CONFIG',
+ os.path.expanduser('~/.notmuch-config'))
+ config.read(conf_f)
+ self._config = config
+ return config
+
+ def _add_new_files_recursively(self, path, db):
+ """:returns: (added, moved, removed)"""
+ print "Enter add new files with path %s" % path
+ (added, moved, removed) = (0,)*3
+
+ try:
+ #get the Directory() object for this path
+ db_dir = db.get_directory(path)
+ except NotmuchError:
+ #Occurs if we have wrong absolute paths in the db, for example
+ return (0,0,0)
+
+
+ #for folder in subdirs:
+
+ #TODO, retrieve dir mtime here and store it later
+ #as long as Filenames() does not allow multiple iteration, we need to
+ #use this kludgy way to get a sorted list of filenames
+ #db_files is a list of subdirectories and filenames in this folder
+ db_files = set()
+ db_folders = set()
+ for subdir in db_dir.get_child_directories():
+ db_folders.add(subdir)
+ for file in db_dir.get_child_files():
+ db_files.add(file)
+
+ fs_files = set(os.listdir(db_dir.path))
+
+ #list of files (and folders) on the fs, but not the db
+ for fs_file in ((fs_files - db_files) - db_folders):
+ absfile = os.path.normpath(os.path.join(db_dir.path, fs_file))
+ statinfo = os.stat(absfile)
+
+ if stat.S_ISDIR(statinfo.st_mode):
+ #This is a directory
+ if fs_file in ['.notmuch','tmp','.']:
+ continue
+ print "%s %s" % (fs_file, db_folders)
+ print "Directory not in db yet. Descending into %s" % absfile
+ (new_added, new_moved, new_removed) = \
+ self._add_new_files_recursively(absfile, db)
+ added += new_added
+ moved += new_moved
+ removed += new_removed
+
+ elif stat.S_ISLNK(statinfo.st_mode):
+ print ("%s is a symbolic link (%d). FIXME!!!" % (absfile, statinfo.st_mode))
+ sys.exit()
+ else:
+ #This is a regular file, not in the db yet. Add it.
+ print "This file needs to be added %s" % (absfile)
+ (msg, status) = db.add_message(absfile)
+ # We increases 'added', even on dupe messages. If it is a moved
+ # message, we will deduct it later and increase 'moved' instead
+ added += 1
+
+ if status == STATUS.DUPLICATE_MESSAGE_ID:
+ #This message was already in the database
+ print "Added msg was in the db"
+ else:
+ print "New message."
+
+ # Finally a list of files (not folders) in the database,
+ # but not the filesystem
+ for db_file in (db_files - fs_files):
+ absfile = os.path.normpath(os.path.join(db_dir.path, db_file))
+
+ #remove a mail message from the db
+ print ("%s is not on the fs anymore. Delete" % absfile)
+ status = db.remove_message(absfile)
+ if status == STATUS.SUCCESS:
+ # we just deleted the last reference, so this was a remove
+ removed += 1
+ sys.stderr.write("SUCCESS %d %s %s.\n" % (status, STATUS.status2str(status), absfile))
+ elif status == STATUS.DUPLICATE_MESSAGE_ID:
+ # The filename exists already somewhere else, so this is a move
+ moved += 1
+ added -= 1
+ sys.stderr.write("DUPE %d %s %s.\n" % (status, STATUS.status2str(status), absfile))
+ else:
+ #This should not occur
+ sys.stderr.write("This should not occur %d %s %s.\n" % (status, STATUS.status2str(status), absfile))
+
+ #list of folders in the filesystem. Just descend into dirs
+ for fs_file in fs_files:
+ absfile = os.path.normpath(os.path.join(db_dir.path, fs_file))
+ if os.path.isdir(absfile):
+ #This is a directory.
+ # Remove it from the db_folder list. All remaining db_folders
+ # at the end will be not present on the file system.
+ db_folders.remove(fs_file)
+ if fs_file in ['.notmuch','tmp','.']:
+ continue
+ (new_added, new_moved, new_removed) = \
+ self._add_new_files_recursively(absfile, db)
+ added += new_added
+ moved += new_moved
+ removed += new_removed
+
+ # we are not interested in anything but directories here
+ #TODO: All remaining elements of db_folders are not in the filesystem
+ #delete those
+
+ return (added, moved, removed)
+ #Read the mtime of a directory from the filesystem
+ #
+ #* Call :meth:`Database.add_message` for all mail files in
+ # the directory
+
+ #* Call notmuch_directory_set_mtime with the mtime read from the
+ # filesystem. Then, when wanting to check for updates to the
+ # directory in the future, the client can call :meth:`get_mtime`
+ # and know that it only needs to add files if the mtime of the
+ # directory and files are newer than the stored timestamp.
+
+ def get_user_email_addresses(self):
+ """ Reads a user's notmuch config and returns his email addresses as
+ list (name, primary_address, other_address1,...)"""