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())
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())
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
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))
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))
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
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))
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))