Ejemplo n.º 1
0
def import_folder(node, filename, task=None):
    """
    Import a folder tree as a subfolder of the current item

    node     -- node to attach folder to
    filename -- filename of folder to import
    task     -- Task object to track progress
    """

    # TODO: Exceptions, intelligent error handling
    # For windows:
    # Deep paths are handled by unicode "\\?\" extension to filename.

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()

    # Determine number of files in advance so we can have a progress bar
    nfiles = 0
    nfilescomplete = 0  # updates progress bar
    for root, dirs, files in os.walk(filename):
        nfiles += len(files)  # Add files found in current dir
        task.set_message(("text", "Found %i files..." % nfiles))

    # Make a node based on the root - so we have an origin to import to
    rootnode = node.new_child(CONTENT_TYPE_DIR, os.path.basename(filename))
    rootnode.set_attr("title", os.path.basename(filename))
    filename2node = {filename: rootnode}

    # Walk directory we're importing and create nodes
    for root, dirs, files in os.walk(filename):

        # create node for directory
        if root == filename:
            parent = rootnode
        else:
            parent2 = filename2node.get(os.path.dirname(root), None)
            if parent2 is None:
                continue

            parent = parent2.new_child(CONTENT_TYPE_DIR,
                                       os.path.basename(root))
            parent.set_attr("title", os.path.basename(root))
            filename2node[root] = parent

        # create nodes for files
        for fn in files:
            if keepnote.get_platform() is "windows":
                fn = "\\\\?\\" + os.path.join(root, fn)
            else:
                fn = os.path.join(root, fn)
            child = attach_file(fn, parent)

            nfilescomplete += 1
            task.set_message(
                ("text",
                 "Imported %i / %i files..." % (nfilescomplete, nfiles)))
            task.set_percent(float(nfilescomplete) / float(nfiles))

    task.finish()
Ejemplo n.º 2
0
    def export_notebook(self, notebook, filename, window=None):

        if notebook is None:
            return

        if window:

            task = tasklib.Task(
                lambda task: export_notebook(notebook, filename, task))

            window.wait_dialog(
                "Exporting to '%s'..." % os.path.basename(filename),
                "Beginning export...", task)

            # check exceptions
            try:
                ty, error, tracebk = task.exc_info()
                if error:
                    raise error
                window.set_status("Notebook exported")
                return True

            except NoteBookError, e:
                window.set_status("")
                window.error("Error while exporting notebook:\n%s" % e.msg, e,
                             tracebk)
                return False

            except Exception, e:
                window.set_status("")
                window.error("unknown error", e, tracebk)
                return False
Ejemplo n.º 3
0
    def restore_notebook(self, archive_filename, notebook_filename,
                         window=None):
        """Restore notebook"""

        if window:

            # make sure current notebook is closed
            window.close_notebook()

            task = tasklib.Task(lambda task:
                restore_notebook(archive_filename, notebook_filename, True, task))

            window.wait_dialog("Restoring notebook from '%s'..." %
                               os.path.basename(archive_filename),
                               "Opening archive...",
                               task)

            # check exceptions
            try:
                ty, error, tracebk = task.exc_info()
                if error:
                    raise error
                window.set_status("Notebook restored")

            except NoteBookError, e:
                window.set_status("")
                window.error("Error restoring notebook:\n%s" % e.msg, e, tracebk)
                return

            except Exception, e:
                window.set_status("")
                window.error("unknown error", e, tracebk)
                return
Ejemplo n.º 4
0
    def archive_notebook(self, notebook, filename, window=None):
        """Archive a notebook"""

        if notebook is None:
            return

        task = tasklib.Task(
            lambda task: archive_notebook(notebook, filename, task))

        if window:

            window.wait_dialog(
                "Creating archive '%s'..." % os.path.basename(filename),
                "Beginning archive...", task)

            # check exceptions
            try:
                ty, error, tracebk = task.exc_info()
                if error:
                    raise error
                window.set_status("Notebook archived")
                return True

            except NoteBookError, e:
                window.set_status("")
                window.error("Error while archiving notebook:\n%s" % e.msg, e,
                             tracebk)
                return False

            except Exception, e:
                window.set_status("")
                window.error("unknown error", e, tracebk)
                return False
    def show(self, notebook_filename, version=None, task=None):

        self.xml = gtk.glade.XML(get_resource("rc", "keepnote.glade"),
                                 "update_notebook_dialog",
                                 keepnote.GETTEXT_DOMAIN)
        self.dialog = self.xml.get_widget("update_notebook_dialog")
        self.xml.signal_autoconnect(self)
        self.dialog.connect(
            "close", lambda w: self.dialog.response(gtk.RESPONSE_CANCEL))
        self.dialog.set_transient_for(self.main_window)

        self.text = self.xml.get_widget("update_message_label")
        self.saved = self.xml.get_widget("save_backup_check")

        if version is None:
            version = notebooklib.get_notebook_version(notebook_filename)

        self.text.set_text(MESSAGE_TEXT %
                           (version, notebooklib.NOTEBOOK_FORMAT_VERSION))

        ret = False
        response = self.dialog.run()

        if response == gtk.RESPONSE_OK:

            # do backup
            if self.saved.get_active():
                if not self.backup(notebook_filename):
                    self.dialog.destroy()
                    return False

            self.dialog.destroy()

            # do update
            def func(task):
                update.update_notebook(notebook_filename,
                                       notebooklib.NOTEBOOK_FORMAT_VERSION)

            # TODO: reuse existing task
            task = tasklib.Task(func)
            dialog2 = dialog_wait.WaitDialog(self.main_window)
            dialog2.show(_("Updating Notebook"),
                         _("Updating notebook..."),
                         task,
                         cancel=False)

            ret = not task.aborted()
            ty, err, tb = task.exc_info()
            if err:
                self.main_window.error(_("Error while updating."), err, tb)
                ret = False
        else:
            self.dialog.destroy()

        if ret:
            self.app.message(_("Notebook updated successfully"),
                             _("Notebook Update Complete"), self.main_window)

        return ret
    def backup(self, notebook_filename):

        dialog = FileChooserDialog(
            _("Choose Backup Notebook Name"),
            self.main_window,
            action=gtk.FILE_CHOOSER_ACTION_SAVE,  #CREATE_FOLDER,
            buttons=(_("Cancel"), gtk.RESPONSE_CANCEL, _("Backup"),
                     gtk.RESPONSE_OK),
            app=self.app,
            persistent_path="new_notebook_path")

        response = dialog.run()

        new_filename = dialog.get_filename()
        dialog.destroy()

        if response == gtk.RESPONSE_OK and new_filename:
            new_filename = unicode_gtk(new_filename)

            def func(task):
                try:
                    shutil.copytree(notebook_filename, new_filename)
                except Exception as e:
                    print(e, file=sys.stderr)
                    print("'%s' '%s'" % (notebook_filename, new_filename),
                          file=sys.stderr)
                    raise

            task = tasklib.Task(func)
            dialog2 = dialog_wait.WaitDialog(self.dialog)
            dialog2.show(_("Backing Up Notebook"),
                         _("Backing up old notebook..."),
                         task,
                         cancel=False)

            # handle errors
            if task.aborted():
                ty, err, tb = task.exc_info()
                if err:
                    self.main_window.error(_("Error occurred during backup."),
                                           err, tb)
                else:
                    self.main_window.error(_("Backup canceled."))
                return False

        return True
Ejemplo n.º 7
0
def export_notebook(notebook, filename, task):
    """Export notebook to HTML

       filename -- filename of export to create
    """

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()

    if os.path.exists(filename):
        raise NoteBookError("File '%s' already exists" % filename)

    # make sure all modifications are saved first
    try:
        notebook.save()
    except Exception, e:
        raise NoteBookError("Could not save notebook before archiving", e)
Ejemplo n.º 8
0
def import_txt(node, filename, index=None, task=None):
    """
    Import a text file into the notebook

    node     -- node to attach folder to
    filename -- filename of text file to import
    task     -- Task object to track progress
    """

    # TODO: handle spaces correctly

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()

    child = node.new_child(notebooklib.CONTENT_TYPE_PAGE,
                           os.path.basename(filename), index)
    child.set_attr("title", os.path.basename(filename))  # remove for 0.6.4

    lines = open(filename).readlines()

    out = safefile.open(child.get_data_file(), "w", codec="utf-8")
    out.write(
        u"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><body>""")

    lines = [escape_whitespace(escape(line)) for line in lines]
    text = "".join(lines)

    # replace newlines
    text = text.replace(u"\n", u"<br/>")
    text = text.replace(u"\r", u"")

    out.write(text)
    out.write(u"</body></html>")

    out.close()
    task.finish()
Ejemplo n.º 9
0
def make_catalog_page(child,text,task) :
        #node, filename, index=None, task=None):
    """
    Insert a listing of files into current page

    child     -- write into this node
    text -- formatted listing of files or content to insert into page
    task     -- Task object to track progress

    filename -- filename of text file to import
    """

    # TODO: handle spaces correctly

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()
    

    #child = node.new_child(notebooklib.CONTENT_TYPE_PAGE, os.path.basename(filename), index)
    #child.set_attr("title", os.path.basename(filename)) # remove for 0.6.4

    #text = open(filename).read()
    
    out = safefile.open(child.get_data_file(), "w", codec="utf-8")
    out.write(u"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><body>""")

    #text = escape(text)
    text = text.replace(u"\n", u"<br/>")
    text = text.replace(u"\r", u"")

    out.write(text)
    out.write(u"</body></html>")

    out.close()
    task.finish()      
Ejemplo n.º 10
0
def archive_notebook(notebook, filename, task=None):
    """Archive notebook as *.tar.gz

       filename -- filename of archive to create
    """

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()


    if os.path.exists(filename):
        raise NoteBookError("File '%s' already exists" % filename)

    # make sure all modifications are saved first
    try:
        notebook.save()
    except Exception as e:
        raise NoteBookError("Could not save notebook before archiving", e)


    # perform archiving
    archive = tarfile.open(filename, "w:gz", format=tarfile.PAX_FORMAT)
    path = notebook.get_path()

    # first count # of files
    nfiles = 0
    for root, dirs, files in os.walk(path):
        nfiles += len(files)

    task.set_message(("text", "Archiving %d files..." % nfiles))

    nfiles2 = [0]
    def walk(path, arcname):
        # add to archive
        archive.add(path, arcname, False)

        # report progresss
        if os.path.isfile(path):
            nfiles2[0] += 1
            if task:
                task.set_message(("detail", truncate_filename(path)))
                task.set_percent(nfiles2[0] / float(nfiles))


        # recurse
        if os.path.isdir(path):
            for f in os.listdir(path):

                # abort archive
                if task.aborted():
                    archive.close()
                    os.remove(filename)
                    raise NoteBookError("Backup canceled")

                if not os.path.islink(f):
                    walk(os.path.join(path, f),
                         os.path.join(arcname, f))

    walk(path, os.path.basename(path))

    task.set_message(("text", "Closing archive..."))
    task.set_message(("detail", ""))

    archive.close()

    if task:
        task.finish()
Ejemplo n.º 11
0
def import_nmap(node, filename, index=None, task=None):
    """
    Import a nmap XML single file into the notebook

    node     -- node to attach folder to
    filename -- filename of text file to import
    task     -- Task object to track progress
    """

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()

    nmapxml = minidom.parse(filename)

    for hostnode in nmapxml.getElementsByTagName("host"):
        ip = ''
        mac = ''
        dns_a = []
        dns_ptr = []

        if len(hostnode.getElementsByTagName("address")) > 0:
            ip = hostnode.getElementsByTagName("address")[0].getAttribute(
                "addr")
            if len(hostnode.getElementsByTagName("address")) > 1:
                mac = hostnode.getElementsByTagName("address")[1].getAttribute(
                    "addr")
                mac += " " + hostnode.getElementsByTagName(
                    "address")[1].getAttribute("vendor")

        if len(hostnode.getElementsByTagName("hostnames")) > 0:
            for hostname in hostnode.getElementsByTagName(
                    "hostnames")[0].getElementsByTagName("hostname"):
                if hostname.getAttribute("type") == "user":
                    dns_a.append(hostname.getAttribute("name"))
                elif hostname.getAttribute("type") == "PTR":
                    dns_ptr.append(hostname.getAttribute("name"))

        hostinfo = "{ip} {hostnames} {mac}".format(ip=ip,
                                                   hostnames=','.join(dns_a +
                                                                      dns_ptr),
                                                   mac=mac)
        host = node.new_child(notebooklib.CONTENT_TYPE_PAGE, hostinfo)
        host.set_attr("title", hostinfo)
        with safefile.open(host.get_data_file(), "w", codec="utf-8") as o:
            o.write(
                """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
            )
            if mac:
                o.write('<span>%s</span><br/>' % mac)
            for hostname in dns_a:
                o.write('<span style="color: #00ff00">%s A</span><br/>' %
                        hostname)
            for hostname in dns_ptr:
                o.write('<span style="color: #00ffff">%s PTR</span><br/>' %
                        hostname)
            o.write("</body></html>")
            o.close()

        #host.set_attr("icon","note-green.png")

        if len(hostnode.getElementsByTagName("ports")) > 0:
            for portnode in hostnode.getElementsByTagName(
                    "ports")[0].getElementsByTagName("port"):
                pnumber = portnode.getAttribute("portid")
                pprotocol = portnode.getAttribute("protocol")

                if len(portnode.getElementsByTagName("state")) > 0:
                    statenode = portnode.getElementsByTagName("state")[0]
                    pstate = statenode.getAttribute("state")
                    pstatereason = statenode.getAttribute("reason")
                    pttl = statenode.getAttribute("reason_ttl")

                if len(portnode.getElementsByTagName("service")) > 0:
                    servicenode = portnode.getElementsByTagName("service")[0]
                    pservicename = servicenode.getAttribute("name")
                    pserviceproduct = servicenode.getAttribute("product")
                    pserviceversion = servicenode.getAttribute("version")
                    pextrainfo = servicenode.getAttribute("extrainfo")

                serviceinfo = "{service} {ver}".format(
                    service=pserviceproduct,
                    ver=pserviceversion) if pserviceproduct else pservicename
                portinfo = "{port}/{proto} ttl={ttl} {service}".format(
                    port=pnumber,
                    proto=pprotocol,
                    ttl=pttl,
                    service=serviceinfo)
                port = host.new_child(notebooklib.CONTENT_TYPE_PAGE, portinfo)
                port.set_attr("title", portinfo)
                with safefile.open(port.get_data_file(), "w",
                                   codec="utf-8") as o:
                    o.write(
                        """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
                    )
                    o.write(
                        "Service: %s<br/>Product: %s<br/>Version: %s<br/>Info: %s<br/>"
                        % (pservicename, pserviceproduct, pserviceversion,
                           pextrainfo))
                    o.write("</body></html>")
                    o.close()
                if pstate == 'open':
                    port.set_attr("title_fgcolor", "#00AA00")
                elif pstate == 'filtered':
                    port.set_attr("title_fgcolor", "#555555")
                elif pstate == 'closed':
                    port.set_attr("title_fgcolor", "#000000")

    task.finish()
Ejemplo n.º 12
0
def import_nmap(node, filename, index=None, task=None):
    """
    Import a nmap XML single file into the notebook

    node     -- node to attach folder to
    filename -- filename of text file to import
    task     -- Task object to track progress
    """

    # TODO: handle spaces correctly

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()

    nmapxml = minidom.parse(filename)

    # Searching for up and down numbers
    nhostup = nmapxml.getElementsByTagName("hosts")[0].getAttribute("up")
    nhostdown = nmapxml.getElementsByTagName("hosts")[0].getAttribute("down")
    scanstats = "(%s up, %s down)" % (nhostup, nhostdown)
    originaltitle = node.get_attr("title")
    node.set_attr("title", "%s %s" % (originaltitle, scanstats))

    # Create a Up and Down folder
    uphostsfolder = node.new_child(notebooklib.CONTENT_TYPE_DIR, ("Up"), index)
    uphostsfolder.set_attr("title", ("Up (%s)" % nhostup))
    # Create a Up and Down folder
    downhostsfolder = node.new_child(notebooklib.CONTENT_TYPE_DIR, ("Down"),
                                     index)
    downhostsfolder.set_attr("title", ("Down (%s)" % nhostdown))

    noportsopenfolder = uphostsfolder.new_child(notebooklib.CONTENT_TYPE_DIR,
                                                ("No Ports Open"), index)
    noportsopenfolder.set_attr("title", ("No Ports Open"))
    withportsopenfolder = uphostsfolder.new_child(notebooklib.CONTENT_TYPE_DIR,
                                                  ("With Ports Open"), index)
    withportsopenfolder.set_attr("title", "With Ports Open")

    for hostnode in nmapxml.getElementsByTagName("host"):

        hstatus = "Unknown"
        hstatusreason = "Unknown"
        hstatusreasonttl = "Unknown"
        haddress = "Unknown"
        hosfirstmatch = None
        newhostnode = None
        icon = None
        detectedos = []

        if len(hostnode.getElementsByTagName("status")) > 0:
            hstatusnode = hostnode.getElementsByTagName("status")[0]
            hstatus = hstatusnode.getAttribute("state")
            hstatusreason = hstatusnode.getAttribute("reason")
            hstatusreasonttl = hstatusnode.getAttribute("reason_ttl")

        if (len(hostnode.getElementsByTagName("address")) > 0):
            haddress = hostnode.getElementsByTagName(
                "address")[0].getAttribute("addr")

        if len(hostnode.getElementsByTagName("os")) > 0:
            oscount = 0
            for osmatch in hostnode.getElementsByTagName(
                    "os")[0].getElementsByTagName("osmatch"):
                osname = osmatch.getAttribute("name")
                osaccuracy = osmatch.getAttribute("accuracy")
                osfamily = osmatch.getElementsByTagName(
                    "osclass")[0].getAttribute("osfamily")
                if osfamily is None:
                    osfamily = osmatch.getElementsByTagName(
                        "osclass")[0].getAttribute("family")
                osvendor = osmatch.getElementsByTagName(
                    "osclass")[0].getAttribute("vendor")
                ostype = osmatch.getElementsByTagName(
                    "osclass")[0].getAttribute("type")
                detectedos.append(
                    [osname, osaccuracy, ostype, osvendor, osfamily])
                if oscount == 0:
                    hosfirstmatch = osname
                    icon = get_os_icon(hosfirstmatch)
                oscount += 1

            # If no OS was identified by nmap
            if oscount == 0:
                mypath = os.path.dirname(os.path.abspath(__file__))
                icon = "%s/icons/question.png" % mypath

        # Create the folder with the first IP obtained and the fist hostname
        hnames = []
        if len(hostnode.getElementsByTagName("hostnames")) > 0:
            for hostname in hostnode.getElementsByTagName(
                    "hostnames")[0].getElementsByTagName("hostname"):
                hnames.append([
                    hostname.getAttribute("name"),
                    hostname.getAttribute("type")
                ])

        if len(hnames) == 0:
            mainhostname = haddress
        else:
            if hnames[0][0] is not None:
                mainhostname = hnames[0][0]
            else:
                mainhostname = haddress

        # New host node hanging from "Up" or "Down" folder
        if (hstatus == "up"):
            if len(hostnode.getElementsByTagName("ports")) > 0:
                newhostnode = withportsopenfolder.new_child(
                    notebooklib.CONTENT_TYPE_DIR,
                    ("%s - %s") % (haddress, mainhostname), index)
            else:
                newhostnode = noportsopenfolder.new_child(
                    notebooklib.CONTENT_TYPE_DIR,
                    ("%s - %s") % (haddress, mainhostname), index)
        else:
            newhostnode = downhostsfolder.new_child(
                notebooklib.CONTENT_TYPE_DIR,
                ("%s - %s") % (haddress, mainhostname), index)
        newhostnode.set_attr("title", ("%s - %s") % (haddress, mainhostname))

        # Create a page with status reason of the host and other information
        statusnode = newhostnode.new_child(notebooklib.CONTENT_TYPE_PAGE,
                                           "Status Information", None)
        statusout = safefile.open(statusnode.get_data_file(),
                                  "w",
                                  codec="utf-8")
        statusout.write(
            """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
        )
        statusout.write("<b>Status:</b> %s<br/>" % hstatus)
        statusout.write("<b>Status Reason:</b> %s<br/>" % hstatusreason)
        statusout.write("<b>Status Reason TTL:</b> %s<br/>" % hstatusreasonttl)
        statusout.write("</body></html>")
        statusout.close()

        if len(hostnode.getElementsByTagName("os")) > 0:
            osinfonode = newhostnode.new_child(notebooklib.CONTENT_TYPE_PAGE,
                                               "OS Information", None)
            osinfonode = safefile.open(osinfonode.get_data_file(),
                                       "w",
                                       codec="utf-8")
            osinfonode.write(
                """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
            )

            if icon is not None:
                osinfonode.write("<br/>")
                osinfonode.write("<img src=\"%s\"/><br/>" % icon)

            for detected_os in detectedos:
                osinfonode.write("-----------------------------------<br/>")
                osinfonode.write("<b>OS Name:</b> %s<br/>" % detected_os[0])
                osinfonode.write("<b>OS Accuracy:</b> %s<br/>" %
                                 detected_os[1])
                osinfonode.write("<b>OS Type:</b> %s<br/>" % detected_os[2])
                osinfonode.write("<b>OS Vendor:</b> %s<br/>" % detected_os[3])
                osinfonode.write("<b>OS Family:</b> %s<br/>" % detected_os[4])
                osinfonode.write("-----------------------------------<br/>")

            osinfonode.write("</body></html>")
            osinfonode.close()

        # Icon selection
        if icon is not None:
            print "Setting the icon for host %s to %s" % (haddress, icon)
            newhostnode.set_attr("icon", icon)
        else:
            # Change the color of the Host depending on the state (Up: Green, Dow: Red)
            if hstatus == "up":
                # Green
                newhostnode.set_attr("icon", "folder-green.png")
            else:
                # Red
                newhostnode.set_attr("icon", "folder-red.png")

        # Change the color of the Host depending on the state (Up: Green, Dow: Red)
        if hstatus == "up":
            # Green
            newhostnode.set_attr("title_fgcolor", "#00AA00")
        else:
            # Red
            newhostnode.set_attr("title_fgcolor", "#AA0000")

        # Create a page with multiple hostnames of this host
        if len(hnames) > 0:
            hostnamenode = newhostnode.new_child(notebooklib.CONTENT_TYPE_PAGE,
                                                 "Hostnames", None)
            hostnameout = safefile.open(hostnamenode.get_data_file(),
                                        "w",
                                        codec="utf-8")
            hostnameout.write(
                """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
            )
            for hnametype in hnames:
                hostnameout.write(
                    ("<b>Hostname:</b> %s. <b>Type:</b> %s<br/>") %
                    (hnametype[0], hnametype[1]))
            hostnameout.write("</body></html>")
            hostnameout.close()

        # If this host has any port information
        if len(hostnode.getElementsByTagName("ports")) > 0:
            n_udpopen = 0
            n_udpclosed = 0
            n_udpfiltered = 0
            n_tcpopen = 0
            n_tcpclosed = 0
            n_tcpfiltered = 0
            # Create a folder for TCP Ports
            tcpportfolder = newhostnode.new_child(notebooklib.CONTENT_TYPE_DIR,
                                                  ("TCP"), index)
            tcpportfolder.set_attr("title", ("TCP"))

            # Create a folder for UDP Ports
            udpportfolder = newhostnode.new_child(notebooklib.CONTENT_TYPE_DIR,
                                                  ("UDP"), index)
            udpportfolder.set_attr("title", ("UDP"))

            for port in hostnode.getElementsByTagName(
                    "ports")[0].getElementsByTagName("port"):

                pstate = "Unknown"
                pstatereason = "Unknown"
                pservicename = "Unknown"
                pserviceproduct = "Unknown"
                pserviceversion = "Unknown"
                pserviceostype = "Unknown"

                pnumber = port.getAttribute("portid")
                pprotocol = port.getAttribute("protocol")

                if len(port.getElementsByTagName("state")) > 0:
                    statenode = port.getElementsByTagName("state")[0]
                    pstate = statenode.getAttribute("state")
                    pstatereason = statenode.getAttribute("reason")

                if len(port.getElementsByTagName("service")) > 0:
                    servicenode = port.getElementsByTagName("service")[0]
                    pservicename = servicenode.getAttribute("name")
                    pserviceproduct = servicenode.getAttribute("product")
                    pserviceversion = servicenode.getAttribute("version")
                    pserviceostype = servicenode.getAttribute("ostype")

                newportchild = None
                if pprotocol.upper() == "TCP":
                    # Create the page node fot TCP
                    newportchild = tcpportfolder.new_child(
                        notebooklib.CONTENT_TYPE_PAGE, ("%s_%s - %s [%s]") %
                        (pnumber, pprotocol, pservicename, pstate))
                    newportchild.set_attr(
                        "title", ("%s_%s - %s [%s]") %
                        (pnumber, pprotocol, pservicename, pstate))
                    # Save port status stats
                    if (pstate.upper() == "OPEN"):
                        n_tcpopen += 1
                    elif (pstate.upper() == "CLOSED"):
                        n_tcpclosed += 1
                    else:
                        n_tcpfiltered += 1
                else:
                    # Create the page node fot UDP
                    newportchild = udpportfolder.new_child(
                        notebooklib.CONTENT_TYPE_PAGE, ("%s_%s - %s [%s]") %
                        (pnumber, pprotocol, pservicename, pstate))
                    newportchild.set_attr(
                        "title", ("%s_%s - %s [%s]") %
                        (pnumber, pprotocol, pservicename, pstate))
                    # Save port status stats
                    if (pstate.upper() == "OPEN"):
                        n_udpopen += 1
                    elif (pstate.upper() == "CLOSED"):
                        n_udpclosed += 1
                    else:
                        n_udpfiltered += 1

                portout = safefile.open(newportchild.get_data_file(),
                                        "w",
                                        codec="utf-8")
                portout.write(
                    """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
                )
                portout.write((
                    "<b>Port Number:</b> %s. <b>Protocol:</b> %s. <b>State:</b> %s. <b>State Reason:</b> %s<br/>"
                ) % (pnumber, pprotocol, pstate, pstatereason))
                portout.write((
                    "<b>Service:</b> %s. <b>Product:</b> %s. <b>version:</b> %s. <b>OS Type:</b> %s<br/>"
                ) % (pservicename, pserviceproduct, pserviceversion,
                     pserviceostype))
                portout.write("</body></html>")
                portout.close()

                # Change the color of the note depending on the state (Open: Green, Closed: Red, Filtered: Orange)
                if pstate == "open":
                    # Green
                    newportchild.set_attr("icon", "note-green.png")
                    newportchild.set_attr("title_fgcolor", "#00AA00")
                elif pstate == "filtered" or pstate == "open|filtered":
                    # Orange
                    newportchild.set_attr("icon", "note-orange.png")
                    newportchild.set_attr("title_fgcolor", "#ffa300")
                else:
                    # Red
                    newportchild.set_attr("icon", "note-red.png")
                    newportchild.set_attr("title_fgcolor", "#AA0000")

            # Update Ports UPD/TCP Stats in the title
            # For TCP
            portstats = ""
            if (n_tcpopen > 0):
                portstats += "%s open" % n_tcpopen
            if (n_tcpclosed > 0):
                if (len(portstats) > 0):
                    portstats += ","
                portstats += "%s closed" % n_tcpclosed
            if (n_tcpfiltered > 0):
                if (len(portstats) > 0):
                    portstats += ","
                portstats += "%s filtered" % n_tcpfiltered
            if (len(portstats) > 0):
                tcpportfolder.set_attr("title", "TCP (%s)" % portstats)
            # For UDP
            portstats = ""
            if (n_udpopen > 0):
                portstats += "%s open" % n_udpopen
            if (n_udpclosed > 0):
                if (len(portstats) > 0):
                    portstats += ","
                portstats += "%s closed" % n_udpclosed
            if (n_udpfiltered > 0):
                if (len(portstats) > 0):
                    portstats += ","
                portstats += "%s filtered" % n_udpfiltered
            if (len(portstats) > 0):
                udpportfolder.set_attr("title", "UDP (%s)" % portstats)

    task.finish()
Ejemplo n.º 13
0
    def open_notebook(self, filename, window=None, task=None):
        """Open notebook"""

        from keepnote.gui import dialog_update_notebook

        # HACK
        if isinstance(self._conns.get(filename),
                      keepnote.notebook.connection.fs.NoteBookConnectionFS):

            try:
                version = notebooklib.get_notebook_version(filename)
            except Exception as e:
                self.error(
                    _("Could not load notebook '%s'.") % filename, e,
                    sys.exc_info()[2])
                return None

            if version < notebooklib.NOTEBOOK_FORMAT_VERSION:
                dialog = dialog_update_notebook.UpdateNoteBookDialog(
                    self, window)
                if not dialog.show(filename, version=version, task=task):
                    self.error(_("Cannot open notebook (version too old)"))
                    gtk.gdk.threads_leave()
                    return None

        # load notebook in background
        def update(task):
            sem = threading.Semaphore()
            sem.acquire()

            # perform notebook load in gui thread.
            # Ideally, this should be in the background, but it is very
            # slow.  If updating the wait dialog wasn't so expensive, I would
            # simply do loading in the background thread.
            def func():
                try:
                    conn = self._conns.get(filename)
                    notebook = notebooklib.NoteBook()
                    notebook.load(filename, conn)
                    task.set_result(notebook)
                except Exception as e:
                    task.set_exc_info()
                    task.stop()
                sem.release()  # notify that notebook is loaded
                return False

            gobject.idle_add(func)

            # wait for notebook to load
            sem.acquire()

        def update_old(task):
            notebook = notebooklib.NoteBook()
            notebook.load(filename)
            task.set_result(notebook)

        task = tasklib.Task(update)
        dialog = keepnote.gui.dialog_wait.WaitDialog(window)
        dialog.show(_("Opening notebook"), _("Loading..."), task, cancel=False)

        # detect errors
        try:
            if task.aborted():
                raise task.exc_info()[1]
            else:
                notebook = task.get_result()
                if notebook is None:
                    return None

        except notebooklib.NoteBookVersionError as e:
            self.error(
                _("This version of %s cannot read this notebook.\n"
                  "The notebook has version %d.  %s can only read %d.") %
                (keepnote.PROGRAM_NAME, e.notebook_version,
                 keepnote.PROGRAM_NAME, e.readable_version), e,
                task.exc_info()[2])
            return None

        except NoteBookError as e:
            self.error(
                _("Could not load notebook '%s'.") % filename, e,
                task.exc_info()[2])
            return None

        except Exception as e:
            # give up opening notebook
            self.error(
                _("Could not load notebook '%s'.") % filename, e,
                task.exc_info()[2])
            return None

        self._init_notebook(notebook)

        return notebook
Ejemplo n.º 14
0
class KeepNote(keepnote.KeepNote):
    """GUI version of the KeepNote application instance"""
    def __init__(self, basedir=None):
        keepnote.KeepNote.__init__(self, basedir)

        # window management
        self._current_window = None
        self._windows = []

        # shared gui resources
        self._tag_table = (
            keepnote.gui.richtext.richtext_tags.RichTextTagTable())
        self.init_dialogs()

        # auto save
        self._auto_saving = False  # True if autosave is on
        self._auto_save_registered = False  # True if autosave is registered
        self._auto_save_pause = 0  # >0 if autosave is paused

    def init(self):
        """Initialize application from disk"""
        keepnote.KeepNote.init(self)

    def init_dialogs(self):
        self.app_options_dialog = (
            keepnote.gui.dialog_app_options.ApplicationOptionsDialog(self))
        self.node_icon_dialog = (
            keepnote.gui.dialog_node_icon.NodeIconDialog(self))

    def set_lang(self):
        """Set language for application"""
        keepnote.KeepNote.set_lang(self)

        # setup glade with gettext
        import gtk.glade
        gtk.glade.bindtextdomain(keepnote.GETTEXT_DOMAIN,
                                 keepnote.get_locale_dir())
        gtk.glade.textdomain(keepnote.GETTEXT_DOMAIN)

        # re-initialize dialogs
        self.init_dialogs()

    def load_preferences(self):
        """Load information from preferences"""
        keepnote.KeepNote.load_preferences(self)

        # set defaults for auto save
        p = self.pref
        p.get("autosave_time", default=DEFAULT_AUTOSAVE_TIME)

        # set style
        set_gtk_style(
            font_size=p.get("look_and_feel", "app_font_size", default=10))

        # let windows load their preferences
        for window in self._windows:
            window.load_preferences()

        for notebook in self._notebooks.itervalues():
            notebook.enable_fulltext_search(
                p.get("use_fulltext_search", default=True))

        # start autosave loop, if requested
        self.begin_auto_save()

    def save_preferences(self):
        """Save information into preferences"""

        # let windows save their preferences
        for window in self._windows:
            window.save_preferences()

        keepnote.KeepNote.save_preferences(self)

    #=================================
    # GUI

    def get_richtext_tag_table(self):
        """Returns the application-wide richtext tag table"""
        return self._tag_table

    def new_window(self):
        """Create a new main window"""
        import keepnote.gui.main_window

        window = keepnote.gui.main_window.KeepNoteWindow(self)
        window.connect("delete-event", self._on_window_close)
        window.connect("focus-in-event", self._on_window_focus)
        self._windows.append(window)

        self.init_extensions_windows([window])
        window.show_all()

        if self._current_window is None:
            self._current_window = window

        return window

    def get_current_window(self):
        """Returns the currenly active window"""
        return self._current_window

    def get_windows(self):
        """Returns a list of open windows"""
        return self._windows

    def open_notebook(self, filename, window=None, task=None):
        """Open notebook"""
        from keepnote.gui import dialog_update_notebook

        # HACK
        if isinstance(self._conns.get(filename),
                      keepnote.notebook.connection.fs.NoteBookConnectionFS):

            try:
                version = notebooklib.get_notebook_version(filename)
            except Exception, e:
                self.error(
                    _("Could not load notebook '%s'.") % filename, e,
                    sys.exc_info()[2])
                return None

            if version < notebooklib.NOTEBOOK_FORMAT_VERSION:
                dialog = dialog_update_notebook.UpdateNoteBookDialog(
                    self, window)
                if not dialog.show(filename, version=version, task=task):
                    self.error(_("Cannot open notebook (version too old)"))
                    gtk.gdk.threads_leave()
                    return None

        # load notebook in background
        def update(task):
            sem = threading.Semaphore()
            sem.acquire()

            # perform notebook load in gui thread.
            # Ideally, this should be in the background, but it is very
            # slow.  If updating the wait dialog wasn't so expensive, I would
            # simply do loading in the background thread.
            def func():
                try:
                    conn = self._conns.get(filename)
                    notebook = notebooklib.NoteBook()
                    notebook.load(filename, conn)
                    task.set_result(notebook)
                except Exception:
                    task.set_exc_info()
                    task.stop()
                sem.release()  # notify that notebook is loaded
                return False

            gobject.idle_add(func)

            # wait for notebook to load
            sem.acquire()

        def update_old(task):
            notebook = notebooklib.NoteBook()
            notebook.load(filename)
            task.set_result(notebook)

        task = tasklib.Task(update)
        dialog = keepnote.gui.dialog_wait.WaitDialog(window)
        dialog.show(_("Opening notebook"), _("Loading..."), task, cancel=False)

        # detect errors
        try:
            if task.aborted():
                raise task.exc_info()[1]
            else:
                notebook = task.get_result()
                if notebook is None:
                    return None

        except notebooklib.NoteBookVersionError, e:
            self.error(
                _("This version of %s cannot read this notebook.\n"
                  "The notebook has version %d.  %s can only read %d.") %
                (keepnote.PROGRAM_NAME, e.notebook_version,
                 keepnote.PROGRAM_NAME, e.readable_version), e,
                task.exc_info()[2])
            return None
Ejemplo n.º 15
0
def import_nmap(node, filename, index=None, task=None):
    """
    Import a MSF XML single file into the notebook

    node     -- node to attach folder to
    filename -- filename of text file to import
    task     -- Task object to track progress
    """

    if task is None:
        task = tasklib.Task()

    msfxml = minidom.parse(filename)

    hosts = []
    for hostnode in msfxml.getElementsByTagName("host"):
        if not hostnode.getElementsByTagName("address"):
            continue
        host = Host(ip=hostnode.getElementsByTagName("address")
                    [0].childNodes[0].nodeValue)
        print "[*] parsed host %s" % host.ip
        host.mac = hostnode.getElementsByTagName(
            "mac")[0].childNodes[0].nodeValue if hostnode.getElementsByTagName(
                "mac")[0].childNodes else ''
        host.hostname = hostnode.getElementsByTagName(
            "name"
        )[0].childNodes[0].nodeValue if hostnode.getElementsByTagName(
            "name")[0].childNodes else ''
        host.os = hostnode.getElementsByTagName(
            "os-name"
        )[0].childNodes[0].nodeValue if hostnode.getElementsByTagName(
            "os-name")[0].childNodes else ''
        host.info = hostnode.getElementsByTagName(
            "info"
        )[0].childNodes[0].nodeValue if hostnode.getElementsByTagName(
            "info")[0].childNodes else ''
        host.comments = hostnode.getElementsByTagName(
            "comments"
        )[0].childNodes[0].nodeValue if hostnode.getElementsByTagName(
            "comments")[0].childNodes else ''
        host.vulns = int(
            hostnode.getElementsByTagName("vuln-count")
            [0].childNodes[0].nodeValue) if hostnode.getElementsByTagName(
                "vuln-count")[0].childNodes else 0
        for servicenode in hostnode.getElementsByTagName(
                "services")[0].getElementsByTagName("service"):
            service = Service(port=servicenode.getElementsByTagName("port")
                              [0].childNodes[0].nodeValue)
            service.proto = servicenode.getElementsByTagName(
                "proto")[0].childNodes[0].nodeValue
            service.state = servicenode.getElementsByTagName(
                "state"
            )[0].childNodes[0].nodeValue if servicenode.getElementsByTagName(
                "state")[0].childNodes else ''
            service.name = servicenode.getElementsByTagName(
                "name"
            )[0].childNodes[0].nodeValue if servicenode.getElementsByTagName(
                "name")[0].childNodes else ''
            service.info = servicenode.getElementsByTagName(
                "info"
            )[0].childNodes[0].nodeValue if servicenode.getElementsByTagName(
                "info")[0].childNodes else ''
            host.services.append(service)
        hosts.append(host)

    hosts.sort(key=lambda h: h._id)
    i = 0
    for host in hosts:
        i += 1
        subnetnode = get_subnet(where=node, ip=host.ip)
        if not subnetnode:
            cidr = str(IPNetwork("%s/24" % host.ip).cidr)
            subnetnode = node.new_child(notebooklib.CONTENT_TYPE_PAGE, cidr)
            subnetnode.set_attr("title", cidr)
            with safefile.open(subnetnode.get_data_file(), "w",
                               codec="utf-8") as o:
                o.write(
                    """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
                )
                o.close()
            subnetnode.set_attr("icon", get_net_icon(cidr))

        hostnode = get_hostnode(where=subnetnode, ip=host.ip)
        if not hostnode:
            hostnode = subnetnode.new_child(notebooklib.CONTENT_TYPE_PAGE,
                                            host.ip)
            print "[+] %d/%d added new host %s" % (i, len(hosts), host.ip)
        else:
            print "[+] %d/%d updated host %s" % (i, len(hosts), host.ip)

        #import pdb;pdb.set_trace()
        hostinfo = "{ip} {hostname} {mac}".format(ip=host.ip,
                                                  hostname=host.hostname,
                                                  mac=host.mac)
        hostnode.set_attr("title", hostinfo)
        with safefile.open(hostnode.get_data_file(), "w", codec="utf-8") as o:
            o.write(
                """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
            )
            if host.mac:
                o.write('<span>%s</span><br/>' % host.mac)
            if host.hostname:
                o.write('<span>%s</span><br/>' % host.hostname)
            o.write("</body></html>")
            o.close()

        if get_os_icon(host.os):
            hostnode.set_attr("icon", get_os_icon(host.os))

        if host.vulns > 0:
            hostnode.set_attr("title_fgcolor", "#770000")
            subnetnode.set_attr("title_fgcolor", "#770000")

        if host.comments.find('wned') != -1:
            hostnode.set_attr("title_fgcolor", "#FFFFFF")
            hostnode.set_attr("title_bgcolor", "#770000")
            subnetnode.set_attr("title_fgcolor", "#FFFFFF")
            subnetnode.set_attr("title_bgcolor", "#770000")

        host.services.sort(key=lambda s: s._id)
        for service in host.services:
            servicenode = get_servicenode(where=hostnode, port=service.port)
            if not servicenode:
                servicenode = hostnode.new_child(notebooklib.CONTENT_TYPE_PAGE,
                                                 service.port)
            if service.info and get_software_icon(service.info):
                servicenode.set_attr("icon", get_software_icon(service.info))

            serviceinfo = "{port}/{proto} {name} {info}".format(
                port=service.port,
                proto=service.proto,
                name=service.name,
                info=service.info)
            servicenode.set_attr("title", serviceinfo)
            with safefile.open(servicenode.get_data_file(), "w",
                               codec="utf-8") as o:
                o.write(
                    """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><body>"""
                )
                o.write("<span>%s</span><br/>" % (service.info))
                o.write("</body></html>")
                o.close()

            if service.state == 'filtered':
                servicenode.set_attr("title_fgcolor", "#555555")
            elif service.state == 'closed':
                servicenode.set_attr("title_fgcolor", "#000000")

    task.finish()
Ejemplo n.º 16
0
def export_notebook(notebook, filename, task):
    """Export notebook to HTML

       filename -- filename of export to create
    """

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()

    if os.path.exists(filename):
        raise NoteBookError("File '%s' already exists" % filename)

    # make sure all modifications are saved first
    try:
        notebook.save()
    except Exception as e:
        raise NoteBookError("Could not save notebook before archiving", e)

    # first count # of files
    nnodes = [0]

    def walk(node):
        nnodes[0] += 1
        for child in node.get_children():
            walk(child)

    walk(notebook)

    task.set_message(("text", "Exporting %d notes..." % nnodes[0]))
    nnodes2 = [0]

    def export_page(node, path, arcname):

        filename = os.path.join(path, "page.html")
        filename2 = os.path.join(arcname, "page.html")

        try:
            dom = minidom.parse(filename)

        except Exception as e:
            # error parsing file, use simple file export
            export_files(filename, filename2)

        else:
            translate_links(notebook, path, dom.documentElement)

            # avoid writing <?xml> header
            # (provides compatiability with browsers)
            out = codecs.open(filename2, "wb", "utf-8")
            if dom.doctype:
                dom.doctype.writexml(out)
            dom.documentElement.writexml(out)
            out.close()

    def export_node(node, path, arcname, index=False):

        # look for aborted export
        if task.aborted():
            raise NoteBookError("Backup canceled")

        # report progresss
        nnodes2[0] += 1
        task.set_message(("detail", truncate_filename(path)))
        task.set_percent(nnodes2[0] / float(nnodes[0]))

        skipfiles = set(child.get_basename() for child in node.get_children())

        # make node directory
        os.mkdir(arcname)

        if index:
            write_index(notebook, node, arcname)

        if node.get_attr("content_type") == "text/xhtml+xml":
            skipfiles.add("page.html")
            # export xhtml
            export_page(node, path, arcname)

        # recurse files
        for f in os.listdir(path):
            if not os.path.islink(f) and f not in skipfiles:
                export_files(os.path.join(path, f), os.path.join(arcname, f))

        # recurse nodes
        for child in node.get_children():
            f = child.get_basename()
            export_node(child, os.path.join(path, f), os.path.join(arcname, f))

    def export_files(path, arcname):
        # look for aborted export
        if task.aborted():
            raise NoteBookError("Backup canceled")

        if os.path.isfile(path):
            # copy files
            shutil.copy(path, arcname)

        if os.path.isdir(path):
            # export directory
            os.mkdir(arcname)

            # recurse
            for f in os.listdir(path):
                if not os.path.islink(f):
                    export_files(os.path.join(path, f),
                                 os.path.join(arcname, f))

    export_node(notebook, notebook.get_path(), filename, True)

    task.set_message(("text", "Closing export..."))
    task.set_message(("detail", ""))

    if task:
        task.finish()
Ejemplo n.º 17
0
def restore_notebook(filename, path, rename, task=None):
    """
    Restores a archived notebook

    filename -- filename of archive
    path     -- name of new notebook
    rename   -- if True, path contains notebook name, otherwise path is
                basedir of new notebook
    """

    if task is None:
        # create dummy task if needed
        task = tasklib.Task()


    if path == "":
        raise NoteBookError("Must specify a path for restoring notebook")

    # remove trailing "/"
    path = re.sub("/+$", "", path)

    tar = tarfile.open(filename, "r:gz", format=tarfile.PAX_FORMAT)


    # create new dirctory, if needed
    if rename:
        if not os.path.exists(path):
            tmppath = get_unique_filename(os.path.dirname(path),
                                          os.path.basename(path+"-tmp"))
        else:
            raise NoteBookError("Notebook path already exists")

        try:
            # extract notebook
            members = list(tar.getmembers())

            if task:
                task.set_message(("text", "Restoring %d files..." %
                                  len(members)))

            for i, member in enumerate(members):
                # FIX: tarfile does not seem to keep unicode and str straight
                # make sure member.name is unicode
                if 'path' in member.pax_headers:
                    member.name = member.pax_headers['path']

                if task:
                    if task.aborted():
                        raise NoteBookError("Restore canceled")
                    task.set_message(("detail", truncate_filename(member.name)))
                    task.set_percent(i / float(len(members)))
                tar.extract(member, tmppath)

            files = os.listdir(tmppath)
            # assert len(files) = 1
            extracted_path = os.path.join(tmppath, files[0])
            
            # move extracted files to proper place
            if task:
                task.set_message(("text", "Finishing restore..."))
                shutil.move(extracted_path, path)
                os.rmdir(tmppath)


        except NoteBookError, e:
            raise e
        
        except Exception, e:
            raise NoteBookError("File writing error while extracting notebook", e)
Ejemplo n.º 18
0
def generate_catalog_folders(node, filename, task=None):
    """
    Import a folder tree as a subfolder of the current item

    node     -- node to attach folder to
    filename -- filename of folder to import
    task     -- Task object to track progress
    """

    # TODO: Exceptions, intelligent error handling
    # For windows: 
    # Deep paths are handled by unicode "\\?\" extension to filename.


    if task is None:
        # create dummy task if needed
        task = tasklib.Task()
    

    # Determine number of files in advance so we can have a progress bar
    nfiles = 0
    for root, dirs, files in os.walk(filename):
        nfiles += len(files) # Add files found in current dir
        task.set_message(("text", "Found %i files..." % nfiles))


    # Make a node based on the root - so we have an origin to import to
    rootnode = node.new_child(CONTENT_TYPE_PAGE, os.path.basename(filename))
    rootnode.set_attr("title", os.path.basename(filename))
    filename2node = {filename: rootnode}
    


    nfilescomplete = 0 # updates progress bar


    # Walk directory we're importing and create nodes
    for root, dirs, files in os.walk(filename):
        
        # create node for directory
        if root == filename:
            parent = rootnode
        else:
            parent2 = filename2node.get(os.path.dirname(root), None)
            if parent2 is None:
                keepnote.log_message("parent node not found '%s'.\n" % root)
                continue
            
            parent = parent2.new_child(CONTENT_TYPE_PAGE,
                                       os.path.basename(root))
            parent.set_attr("title", os.path.basename(root))
            filename2node[root] = parent

        
        # create nodes for files
        fileList = "" ;
        for shortName in files:
            #if keepnote.get_platform() is "windows":
            #    fn = "\\\\?\\" + os.path.join(root, fn)
            #else:
            #    fn = os.path.join(root, fn)

            #child = attach_file(fn, parent)
            fn = os.path.join(root,shortName)
            fileSize = os.stat(fn).st_size
            #fileTime = time.asctime(time.localtime(os.stat(fn).st_mtime))
            ft = time.localtime(os.stat(fn).st_mtime)
            fileLine = '<a href="%s">%s</a> %s %02d-%02d-%02d %02d:%02d:%02d ' % (fn,shortName,formatFileSize(fileSize),ft.tm_year,ft.tm_mon,ft.tm_mday,ft.tm_hour,ft.tm_min,ft.tm_sec)

            fileList += fileLine + "\n"  # Will be converted to <br> when page inserted
            nfilescomplete += 1
            task.set_message(("text", "Imported %i / %i files..." % 
                              (nfilescomplete, nfiles)))
            task.set_percent(float(nfilescomplete) / float(nfiles))

        make_catalog_page(parent,fileList,task)

    task.finish()