Example #1
0
def download_and_install(url):
    """
    Downloads and launches the specified file.
    """
    global update_window, url_opener
    try:
        is_cancelled = False
        parent = wx.GetApp().TopWindow
        filename, tmp_dir = os.path.split(url)[-1], tempfile.mkdtemp()
        dlg_progress = \
            controls.ProgressWindow(parent, "Downloading %s" % filename)
        dlg_progress.SetGaugeForegroundColour(conf.GaugeColour)
        dlg_progress.Position = (parent.Position.x + parent.Size.width -
                                 dlg_progress.Size.width, parent.Position.y +
                                 parent.Size.height - dlg_progress.Size.height)
        update_window = dlg_progress
        urlfile = url_opener.open(url)
        filepath = os.path.join(tmp_dir, filename)
        main.log("Downloading %s to %s.", url, filepath)
        filesize = int(urlfile.headers.get("content-length", sys.maxint))
        with open(filepath, "wb") as f:
            BLOCKSIZE = 65536
            bytes_downloaded = 0
            buf = urlfile.read(BLOCKSIZE)
            while len(buf):
                f.write(buf)
                bytes_downloaded += len(buf)
                percent = 100 * bytes_downloaded / filesize
                msg = "%d%% of %s" % (percent, util.format_bytes(filesize))
                is_cancelled = not dlg_progress.Update(percent, msg)
                if is_cancelled:
                    break  # break while len(buf)
                wx.YieldIfNeeded()
                buf = urlfile.read(BLOCKSIZE)
        dlg_progress.Destroy()
        update_window = None
        if is_cancelled:
            main.log("Upgrade cancelled, erasing temporary file %s.", filepath)
            util.try_until(lambda: os.unlink(filepath))
            util.try_until(lambda: os.rmdir(tmp_dir))
        else:
            main.log("Successfully downloaded %s of %s.",
                     util.format_bytes(filesize), filename)
            dlg_proceed = controls.NonModalOKDialog(
                parent, "Update information",
                "Ready to open %s. You should close %s before upgrading." %
                (filename, conf.Title))

            def proceed_handler(event):
                global update_window
                update_window = None
                dlg_proceed.Destroy()
                util.start_file(filepath)

            update_window = dlg_proceed
            dlg_proceed.Bind(wx.EVT_CLOSE, proceed_handler)
    except Exception:
        main.log("Failed to download new version from %s.\n\n%s", url,
                 traceback.format_exc())
Example #2
0
def download_and_install(url):
    """
    Downloads and launches the specified file.
    """
    global update_window, url_opener
    try:
        is_cancelled = False
        parent = wx.GetApp().TopWindow
        filename, tmp_dir = os.path.split(url)[-1], tempfile.mkdtemp()
        dlg_progress = \
            controls.ProgressWindow(parent, "Downloading %s" % filename)
        dlg_progress.SetGaugeForegroundColour(conf.GaugeColour)
        dlg_progress.Position = (
            parent.Position.x + parent.Size.width  - dlg_progress.Size.width,
            parent.Position.y + parent.Size.height - dlg_progress.Size.height)
        update_window = dlg_progress
        urlfile = url_opener.open(url)
        filepath = os.path.join(tmp_dir, filename)
        main.log("Downloading %s to %s.", url, filepath)
        filesize = int(urlfile.headers.get("content-length", sys.maxint))
        with open(filepath, "wb") as f:
            BLOCKSIZE = 65536
            bytes_downloaded = 0
            buf = urlfile.read(BLOCKSIZE)
            while len(buf):
                f.write(buf)
                bytes_downloaded += len(buf)
                percent = 100 * bytes_downloaded / filesize
                msg = "%d%% of %s" % (percent, util.format_bytes(filesize))
                is_cancelled = not dlg_progress.Update(percent, msg)
                if is_cancelled:
                    break # break while len(buf)
                wx.YieldIfNeeded()
                buf = urlfile.read(BLOCKSIZE)
        dlg_progress.Destroy()
        update_window = None
        if is_cancelled:
            main.log("Upgrade cancelled, erasing temporary file %s.", filepath)
            util.try_until(lambda: os.unlink(filepath))
            util.try_until(lambda: os.rmdir(tmp_dir))
        else:
            main.log("Successfully downloaded %s of %s.",
                     util.format_bytes(filesize), filename)
            dlg_proceed = controls.NonModalOKDialog(parent,
                "Update information",
                "Ready to open %s. You should close %s before upgrading."
                % (filename, conf.Title))
            def proceed_handler(event):
                global update_window
                update_window = None
                dlg_proceed.Destroy()
                util.start_file(filepath)
            update_window = dlg_proceed
            dlg_proceed.Bind(wx.EVT_CLOSE, proceed_handler)
    except Exception:
        main.log("Failed to download new version from %s.\n\n%s", url,
                 traceback.format_exc())
Example #3
0
def export_grid(grid, filename, title, db, sql_query="", table=""):
    """
    Exports the current contents of the specified wx.Grid to file.

    @param   grid       a wx.Grid object
    @param   filename   full path and filename of resulting file, file extension
                        .html|.csv|.sql|.xslx determines file format
    @param   title      title used in HTML
    @param   db         SkypeDatabase instance
    @param   sql_query  the SQL query producing the grid contents, if any
    @param   table      name of the table producing the grid contents, if any
    """
    result = False
    f = None
    is_html = filename.lower().endswith(".html")
    is_csv  = filename.lower().endswith(".csv")
    is_sql  = filename.lower().endswith(".sql")
    is_xlsx = filename.lower().endswith(".xlsx")
    try:
        with open(filename, "w") as f:
            columns = [c["name"] for c in grid.Table.columns]

            def iter_rows():
                """Iterating row generator."""
                row, index = grid.Table.GetRow(0), 0
                while row:
                    yield row
                    index += 1; row = grid.Table.GetRow(index)

            if is_csv or is_xlsx:
                if is_csv:
                    dialect = csv.excel
                    dialect.delimiter, dialect.lineterminator = ";", "\r"
                    writer = csv.writer(f, dialect)
                    if sql_query:
                        flat = sql_query.replace("\r", " ").replace("\n", " ")
                        sql_query = flat.encode("latin1", "replace")
                    header = [c.encode("latin1", "replace") for c in columns]
                else:
                    writer = xlsx_writer(filename, table or "SQL Query")
                    writer.set_header(True)
                    header = columns
                if sql_query:
                    a = [[sql_query]] + (["bold", 0, False] if is_xlsx else [])
                    writer.writerow(*a)
                writer.writerow(*([header, "bold"] if is_xlsx else [header]))
                writer.set_header(False) if is_xlsx else 0
                for row in iter_rows():
                    values = []
                    for col in columns:
                        val = "" if row[col] is None else row[col]
                        if is_csv:
                            val = val if isinstance(val, unicode) else str(val)
                            val = val.encode("latin1", "replace")
                        values.append(val)
                    writer.writerow(values)
                writer.close() if is_xlsx else 0
            else:
                namespace = {
                    "db_filename": db.filename,
                    "title":       title,
                    "columns":     columns,
                    "row_count":   grid.NumberRows,
                    "rows":        iter_rows(),
                    "sql":         sql_query,
                    "table":       table,
                    "app":         conf.Title,
                }
                if is_sql and table:
                    # Add CREATE TABLE statement.
                    create_sql = db.tables[table.lower()]["sql"] + ";"
                    re_sql = re.compile("^(CREATE\\s+TABLE\\s+)", re.IGNORECASE)
                    replacer = lambda m: ("%sIF NOT EXISTS " % m.group(1))
                    namespace["create_sql"] = re_sql.sub(replacer, create_sql)

                template = templates.GRID_HTML if is_html else templates.SQL_TXT
                step.Template(template, strip=False).stream(f, namespace)

            result = True
    finally:
        if f: util.try_until(f.close)
    return result
Example #4
0
def export_chat_template(chat, filename, db, messages):
    """
    Exports the chat messages to file using templates.

    @param   chat      chat data dict, as returned from SkypeDatabase
    @param   filename  full path and filename of resulting file, file extension
                       .html|.txt determines file format
    @param   db        SkypeDatabase instance
    @param   messages  list of message data dicts
    """
    tmpfile, tmpname = None, None # Temporary file for exported messages
    try:
        is_html = filename.lower().endswith(".html")
        parser = skypedata.MessageParser(db, chat=chat, stats=True)
        namespace = {"db": db, "chat": chat, "messages": messages,
                     "parser": parser}
        # As HTML and TXT contain statistics in their headers before
        # messages, write out all messages to a temporary file first,
        # statistics will be available for the main file after parsing.
        # Cannot keep all messages in memory at once - very large chats
        # (500,000+ messages) can take gigabytes.
        tmpname = util.unique_path("%s.messages" % filename)
        tmpfile = open(tmpname, "w+")
        mtemplate = templates.CHAT_MESSAGES_HTML if is_html \
                    else templates.CHAT_MESSAGES_TXT
        step.Template(mtemplate, strip=False).stream(tmpfile, namespace)

        namespace["stats"] = stats = parser.get_collected_stats()
        namespace.update({
            "date1": stats["startdate"].strftime("%d.%m.%Y")
                     if stats.get("startdate") else "",
            "date2": stats["enddate"].strftime("%d.%m.%Y")
                     if stats.get("enddate") else "",
            "emoticons_used": [x for x in parser.emoticons_unique
                               if hasattr(emoticons, x)],
            "message_count":  stats.get("messages", 0),
        })

        if is_html:
            # Collect chat and participant images.
            namespace.update({"participants": [], "chat_picture_size": None,
                              "chat_picture_raw": None, })
            if chat["meta_picture"]:
                raw = skypedata.fix_image_raw(chat["meta_picture"])
                namespace["chat_picture_raw"] = raw
                namespace["chat_picture_size"] = util.img_size(raw)

            contacts = dict((c["skypename"], c) for c in db.get_contacts())
            partics = dict((p["identity"], p) for p in chat["participants"])
            # There can be authors not among participants, and vice versa
            for author in stats["authors"].union(partics):
                contact = partics.get(author, {}).get("contact")
                contact = contact or contacts.get(author, {})
                contact = contact or {"identity": author, "name": author}
                bmp = contact.get("avatar_bitmap")
                raw = contact.get("avatar_raw_small") or ""
                raw_large = contact.get("avatar_raw_large") or ""
                if not raw and not bmp:
                    raw = skypedata.get_avatar_raw(contact, conf.AvatarImageSize)
                raw = bmp and util.img_wx_to_raw(bmp) or raw
                if raw:
                    raw_large = raw_large or skypedata.get_avatar_raw(
                                    contact, conf.AvatarImageLargeSize)
                    contact["avatar_raw_small"] = raw
                    contact["avatar_raw_large"] = raw_large
                contact["rank"] = partics.get(author, {}).get("rank")
                namespace["participants"].append(contact)

        tmpfile.flush(), tmpfile.seek(0)
        namespace["message_buffer"] = iter(lambda: tmpfile.read(65536), "")
        template = templates.CHAT_HTML if is_html else templates.CHAT_TXT
        with open(filename, "w") as f:
            step.Template(template, strip=False).stream(f, namespace)
    finally:
        if tmpfile: util.try_until(tmpfile.close)
        if tmpname: util.try_until(lambda: os.unlink(tmpname))
Example #5
0
def export_chat_template(chat, filename, db, messages):
    """
    Exports the chat messages to file using templates.

    @param   chat      chat data dict, as returned from SkypeDatabase
    @param   filename  full path and filename of resulting file, file extension
                       .html|.txt determines file format
    @param   db        SkypeDatabase instance
    @param   messages  list of message data dicts
    """
    tmpfile, tmpname = None, None # Temporary file for exported messages
    try:
        is_html = filename.lower().endswith(".html")
        parser = skypedata.MessageParser(db, chat=chat, stats=is_html)
        namespace = {"db": db, "chat": chat, "messages": messages,
                     "parser": parser}

        if is_html:
            # Collect chat and participant images.
            namespace.update({"participants": [], "chat_picture_size": None,
                              "chat_picture_raw": None, })
            if chat["meta_picture"]:
                raw = skypedata.fix_image_raw(chat["meta_picture"])
                imgparser = ImageFile.Parser(); imgparser.feed(raw)
                img = imgparser.close()
                namespace.update(chat_picture_size=img.size,
                                 chat_picture_raw=raw)
            for p in chat["participants"]:
                contact = p["contact"].copy()
                namespace["participants"].append(contact)
                contact.update(avatar_raw_small="", avatar_raw_large="")
                bmp = contact.get("avatar_bitmap")
                raw = contact.get("avatar_raw_small")
                raw_large = contact.get("avatar_raw_large")
                if not raw and not bmp:
                    raw = skypedata.get_avatar_raw(contact, conf.AvatarImageSize)
                    if raw:
                        p["contact"]["avatar_raw_small"] = raw
                raw = bmp and util.wx_bitmap_to_raw(bmp) or raw
                if raw:
                    if not raw_large:
                        size_large = conf.AvatarImageLargeSize
                        raw_large = skypedata.get_avatar_raw(contact, size_large)
                        p["contact"]["avatar_raw_large"] = raw_large
                    contact["avatar_raw_small"] = raw
                    contact["avatar_raw_large"] = raw_large

        # As HTML and TXT contain statistics in their headers before
        # messages, write out all messages to a temporary file first,
        # statistics will be available for the main file after parsing.
        # Cannot keep all messages in memory at once - very large chats
        # (500,000+ messages) can take gigabytes.
        tmpname = util.unique_path("%s.messages" % filename)
        tmpfile = open(tmpname, "w+")
        mtemplate = templates.CHAT_MESSAGES_HTML if is_html \
                    else templates.CHAT_MESSAGES_TXT
        step.Template(mtemplate, strip=False).stream(tmpfile, namespace)

        namespace["stats"] = stats = parser.get_collected_stats()
        namespace.update({
            "date1": stats["startdate"].strftime("%d.%m.%Y")
                     if stats.get("startdate") else "",
            "date2": stats["enddate"].strftime("%d.%m.%Y")
                     if stats.get("enddate") else "",
            "emoticons_used": list(filter(lambda e: hasattr(emoticons, e),
                                     parser.emoticons_unique)),
            "message_count":  stats.get("messages", 0),
        })

        tmpfile.flush(), tmpfile.seek(0)
        namespace["message_buffer"] = iter(lambda: tmpfile.read(65536), "")
        template = templates.CHAT_HTML if is_html else templates.CHAT_TXT
        with open(filename, "w") as f:
            step.Template(template, strip=False).stream(f, namespace)
    finally:
        if tmpfile: util.try_until(tmpfile.close)
        if tmpname: util.try_until(lambda: os.unlink(tmpname))
Example #6
0
def export_grid(grid, filename, title, db, sql_query="", table=""):
    """
    Exports the current contents of the specified wx.Grid to file.

    @param   grid       a wx.Grid object
    @param   filename   full path and filename of resulting file, file extension
                        .html|.csv|.sql|.xslx determines file format
    @param   title      title used in HTML
    @param   db         SkypeDatabase instance
    @param   sql_query  the SQL query producing the grid contents, if any
    @param   table      name of the table producing the grid contents, if any
    """
    result = False
    f = None
    is_html = filename.lower().endswith(".html")
    is_csv = filename.lower().endswith(".csv")
    is_sql = filename.lower().endswith(".sql")
    is_xlsx = filename.lower().endswith(".xlsx")
    try:
        with open(filename, "w") as f:
            columns = [c["name"] for c in grid.Table.columns]

            def iter_rows():
                """Iterating row generator."""
                row, index = grid.Table.GetRow(0), 0
                while row:
                    yield row
                    index += 1
                    row = grid.Table.GetRow(index)

            if is_csv or is_xlsx:
                if is_csv:
                    dialect = csv.excel
                    dialect.delimiter, dialect.lineterminator = ";", "\r"
                    writer = csv.writer(f, dialect)
                    if sql_query:
                        flat = sql_query.replace("\r", " ").replace("\n", " ")
                        sql_query = flat.encode("latin1", "replace")
                    header = [c.encode("latin1", "replace") for c in columns]
                else:
                    writer = xlsx_writer(filename, table or "SQL Query")
                    writer.set_header(True)
                    header = columns
                if sql_query:
                    a = [[sql_query]] + (["bold", 0, False] if is_xlsx else [])
                    writer.writerow(*a)
                writer.writerow(*([header, "bold"] if is_xlsx else [header]))
                writer.set_header(False) if is_xlsx else 0
                for row in iter_rows():
                    values = []
                    for col in columns:
                        val = "" if row[col] is None else row[col]
                        if is_csv:
                            val = val if isinstance(val, unicode) else str(val)
                            val = val.encode("latin1", "replace")
                        values.append(val)
                    writer.writerow(values)
                writer.close() if is_xlsx else 0
            else:
                namespace = {
                    "db_filename": db.filename,
                    "title": title,
                    "columns": columns,
                    "row_count": grid.NumberRows,
                    "rows": iter_rows(),
                    "sql": sql_query,
                    "table": table,
                    "app": conf.Title,
                }
                if is_sql and table:
                    # Add CREATE TABLE statement.
                    create_sql = db.tables[table.lower()]["sql"] + ";"
                    re_sql = re.compile("^(CREATE\\s+TABLE\\s+)",
                                        re.IGNORECASE)
                    replacer = lambda m: ("%sIF NOT EXISTS " % m.group(1))
                    namespace["create_sql"] = re_sql.sub(replacer, create_sql)

                template = templates.GRID_HTML if is_html else templates.SQL_TXT
                step.Template(template, strip=False).stream(f, namespace)

            result = True
    finally:
        if f: util.try_until(f.close)
    return result
Example #7
0
def export_chat_template(chat, filename, db, messages):
    """
    Exports the chat messages to file using templates.

    @param   chat      chat data dict, as returned from SkypeDatabase
    @param   filename  full path and filename of resulting file, file extension
                       .html|.txt determines file format
    @param   db        SkypeDatabase instance
    @param   messages  list of message data dicts
    """
    tmpfile, tmpname = None, None  # Temporary file for exported messages
    try:
        is_html = filename.lower().endswith(".html")
        parser = skypedata.MessageParser(db, chat=chat, stats=True)
        namespace = {
            "db": db,
            "chat": chat,
            "messages": messages,
            "parser": parser
        }
        # As HTML and TXT contain statistics in their headers before
        # messages, write out all messages to a temporary file first,
        # statistics will be available for the main file after parsing.
        # Cannot keep all messages in memory at once - very large chats
        # (500,000+ messages) can take gigabytes.
        tmpname = util.unique_path("%s.messages" % filename)
        tmpfile = open(tmpname, "w+")
        mtemplate = templates.CHAT_MESSAGES_HTML if is_html \
                    else templates.CHAT_MESSAGES_TXT
        step.Template(mtemplate, strip=False).stream(tmpfile, namespace)

        namespace["stats"] = stats = parser.get_collected_stats()
        namespace.update({
            "date1":
            stats["startdate"].strftime("%d.%m.%Y")
            if stats.get("startdate") else "",
            "date2":
            stats["enddate"].strftime("%d.%m.%Y")
            if stats.get("enddate") else "",
            "emoticons_used":
            [x for x in parser.emoticons_unique if hasattr(emoticons, x)],
            "message_count":
            stats.get("messages", 0),
        })

        if is_html:
            # Collect chat and participant images.
            namespace.update({
                "participants": [],
                "chat_picture_size": None,
                "chat_picture_raw": None,
            })
            if chat["meta_picture"]:
                raw = skypedata.fix_image_raw(chat["meta_picture"])
                namespace["chat_picture_raw"] = raw
                namespace["chat_picture_size"] = util.img_size(raw)

            contacts = dict((c["skypename"], c) for c in db.get_contacts())
            partics = dict((p["identity"], p) for p in chat["participants"])
            # There can be authors not among participants, and vice versa
            for author in stats["authors"].union(partics):
                contact = partics.get(author, {}).get("contact")
                contact = contact or contacts.get(author, {})
                contact = contact or {"identity": author, "name": author}
                bmp = contact.get("avatar_bitmap")
                raw = contact.get("avatar_raw_small") or ""
                raw_large = contact.get("avatar_raw_large") or ""
                if not raw and not bmp:
                    raw = skypedata.get_avatar_raw(contact,
                                                   conf.AvatarImageSize)
                raw = bmp and util.img_wx_to_raw(bmp) or raw
                if raw:
                    raw_large = raw_large or skypedata.get_avatar_raw(
                        contact, conf.AvatarImageLargeSize)
                    contact["avatar_raw_small"] = raw
                    contact["avatar_raw_large"] = raw_large
                contact["rank"] = partics.get(author, {}).get("rank")
                namespace["participants"].append(contact)

        tmpfile.flush(), tmpfile.seek(0)
        namespace["message_buffer"] = iter(lambda: tmpfile.read(65536), "")
        template = templates.CHAT_HTML if is_html else templates.CHAT_TXT
        with open(filename, "w") as f:
            step.Template(template, strip=False).stream(f, namespace)
    finally:
        if tmpfile: util.try_until(tmpfile.close)
        if tmpname: util.try_until(lambda: os.unlink(tmpname))
Example #8
0
def export_chat_template(chat, filename, db, messages):
    """
    Exports the chat messages to file using templates.

    @param   chat      chat data dict, as returned from SkypeDatabase
    @param   filename  full path and filename of resulting file, file extension
                       .html|.txt determines file format
    @param   db        SkypeDatabase instance
    @param   messages  list of message data dicts
    """
    tmpfile, tmpname = None, None  # Temporary file for exported messages
    try:
        is_html = filename.lower().endswith(".html")
        parser = skypedata.MessageParser(db, chat=chat, stats=is_html)
        namespace = {
            "db": db,
            "chat": chat,
            "messages": messages,
            "parser": parser
        }

        if is_html:
            # Collect chat and participant images.
            namespace.update({
                "participants": [],
                "chat_picture_size": None,
                "chat_picture_raw": None,
            })
            if chat["meta_picture"]:
                raw = skypedata.fix_image_raw(chat["meta_picture"])
                imgparser = ImageFile.Parser()
                imgparser.feed(raw)
                img = imgparser.close()
                namespace.update(chat_picture_size=img.size,
                                 chat_picture_raw=raw)
            for p in chat["participants"]:
                contact = p["contact"].copy()
                namespace["participants"].append(contact)
                contact.update(avatar_raw_small="", avatar_raw_large="")
                bmp = contact.get("avatar_bitmap")
                raw = contact.get("avatar_raw_small")
                raw_large = contact.get("avatar_raw_large")
                if not raw and not bmp:
                    raw = skypedata.get_avatar_raw(contact,
                                                   conf.AvatarImageSize)
                    if raw:
                        p["contact"]["avatar_raw_small"] = raw
                raw = bmp and util.wx_bitmap_to_raw(bmp) or raw
                if raw:
                    if not raw_large:
                        size_large = conf.AvatarImageLargeSize
                        raw_large = skypedata.get_avatar_raw(
                            contact, size_large)
                        p["contact"]["avatar_raw_large"] = raw_large
                    contact["avatar_raw_small"] = raw
                    contact["avatar_raw_large"] = raw_large

        # As HTML and TXT contain statistics in their headers before
        # messages, write out all messages to a temporary file first,
        # statistics will be available for the main file after parsing.
        # Cannot keep all messages in memory at once - very large chats
        # (500,000+ messages) can take gigabytes.
        tmpname = util.unique_path("%s.messages" % filename)
        tmpfile = open(tmpname, "w+")
        mtemplate = templates.CHAT_MESSAGES_HTML if is_html \
                    else templates.CHAT_MESSAGES_TXT
        step.Template(mtemplate, strip=False).stream(tmpfile, namespace)

        namespace["stats"] = stats = parser.get_collected_stats()
        namespace.update({
            "date1":
            stats["startdate"].strftime("%d.%m.%Y")
            if stats.get("startdate") else "",
            "date2":
            stats["enddate"].strftime("%d.%m.%Y")
            if stats.get("enddate") else "",
            "emoticons_used":
            list(
                filter(lambda e: hasattr(emoticons, e),
                       parser.emoticons_unique)),
            "message_count":
            stats.get("messages", 0),
        })

        tmpfile.flush(), tmpfile.seek(0)
        namespace["message_buffer"] = iter(lambda: tmpfile.read(65536), "")
        template = templates.CHAT_HTML if is_html else templates.CHAT_TXT
        with open(filename, "w") as f:
            step.Template(template, strip=False).stream(f, namespace)
    finally:
        if tmpfile: util.try_until(tmpfile.close)
        if tmpname: util.try_until(lambda: os.unlink(tmpname))