Blog

Simple Socket-over-HTTP bridge

Have you ever been behind a restricted firewall that only allows HTTP/HTTPS requests, but blocks you from checking Mail via IMAP or sending Mail via SMTP?

If so, this Socket-over-HTTP Bridge can save you the day. However, you need access to an Apache/WSGI enabled server that can act as the other side of the bridge.

→ Read more...

2015/02/20 14:12 · Andreas Böhler

Instead of Facebook...

Normalerweise, als ich noch Facebook hatte, hätte ich heute wohl einen Post gemacht. Stattdessen nutz ich diesmal den Blog :)

Ich sitz im Zug, auf dem Weg nach Wien zum Flughafen. Über Dubai geht's auf nach Sydney!

Kann sein, dass ich den einen oder anderen Blog-Post von Australien aus machen werde…vielleicht sogar mit Photos :)

2015/02/20 14:11 · Andreas Böhler

Authenticate ownCloud against postfixAdmin database

We recently set up an ownCloud hosted site as well as a mailserver based on postfixAdmin. In order to authenticate ownCloud to postfixAdmin, one can use either user_imap oder user_pwauth. Both methods work, but with the drawback that a user list cannot be retrieved.

In order to overcome this limit, I developed a simple app for ownCloud to authenticate against an arbitrary mySQL database. Currently, only the crypt() password method is supported, but database, table and column details can be configured in the admin backend.

You can find the details (and the code!) in my mercurial repository at http://www.aboehler.at/hg/user_sql

2015/02/20 14:10 · Andreas Böhler

Recovering contacts from dead Android phone

A friend of mine recently dropped her Android phone on the floor and the screen cranked - only the backlight would come on, but nothing was displayed. As she didn't sync her contacts, she asked me how to get her contacts back. Here is what I did:

I remembered that I once installed ClockWorkMod recovery alongside with CyanogenMod on the device. Unfortunately, I left USB debugging disabled in Android, as I had hoped to be able to pull the database files via ADB on plugging the phone in. Luckily, CWM comes with ADB debugging enabled, so I booted straight into CWM (on the ZTE Blade by holding down the Vol- button while powering the phone on), attached the phone to the computer and logged in. First step: Mount the data partition with

andy@x200t:~$ adb shell
android:~$ mount /data
android:~$ exit

Then, pull the contacts file:

andy@x200t:~$ adb pull /data/data/com.android.providers.contacts/contacts2.db

This is actually a SQLite database containing all the contact's information. A short research on the internet revealed nothing of interest, so I had to dig myself into the format of the file. I came up with a simple Python converter script, that converts most of the information into a VCard file. Phone numbers are all trated as cell numbers and E-Mail addresses are all treated as home mail addresses. I put question marks on the fields where I suspect lies the relevant information to distinguish the type of phone number, but the information was not consistent in the file. Run the script with the .db file as first parameter and a non-existing .vcf file as second parameter. If the file exists, it will be overwritten without notice. To my big surprise, the resulting .vcf file was accepted by Google Contacts on the first try…

Of course you can also extract the contacts2.db file from e.g. a recent Nandroid backup.

Here is the (ugly, but working) code:

#!/usr/bin/env python2

import sqlite3
import sys
import codecs

class Contact:
    def __init__(self, id):
        self.id = id
        self.phoneNumbers = []
        self.mailAddresses = []
        self.lastname = ""
        self.firstname = ""
        self.hasPhone = False

    def GetPhones(self):
        return self.phoneNumbers

    def AddPhone(self, number):
        self.phoneNumbers.append(number)

    def AddMail(self, mail):
        self.mailAddresses.append(mail)

    def GetMails(self):
        return self.mailAddresses

    def SetFirstname(self, firstname):
        self.firstname = firstname

    def SetLastname(self, lastname):
        self.lastname = lastname

    def GetName(self):
        return (self.lastname, self.firstname)

    def GetId(self):
        return self.id

    def GetVCard(self):
        vcard = []
        vcard.append("BEGIN:VCARD")
        vcard.append("VERSION:2.1")
        vcard.append("N:" + self.lastname + ";" + self.firstname)
        if len(self.lastname) > 0 and len(self.firstname) > 0:
            vcard.append("FN:" + self.firstname + " " + self.lastname)
        elif len(self.lastname) > 0:
            vcard.append("FN:" + self.lastname)
        elif len(self.firstname) > 0:
            vcard.append("FN:" + self.firstname)
        for phone in self.phoneNumbers:
            vcard.append("TEL;type=CELL:" + phone)
        for mail in self.mailAddresses:
            vcard.append("EMAIL;type=INTERNET;type=HOME:" + mail)
        vcard.append("END:VCARD")
        return vcard

if len(sys.argv) < 3:
    sys.exit("Must give filenames as arguments")

fn = sys.argv[1]
db = sqlite3.Connection(fn)
contacts = {}
c = db.cursor()
c.execute("SELECT COUNT(*) FROM contacts")

num_entries = c.fetchone()[0]

print "Getting " + str(num_entries) + " contacts..."

c.execute("SELECT name_raw_contact_id, has_phone_number FROM contacts")

while True:
    row = c.fetchone()
    if row is None: break
    if not contacts.has_key(row[0]):
        contacts[row[0]] = Contact(row[0])
        contacts[row[0]].hasPhone = row[1]

for key in contacts.keys():
    c.execute("SELECT mimetype_id, data_version, data1, data2, data3 FROM data WHERE raw_contact_id = " + str(contacts[key].GetId()))
    while True:
        row = c.fetchone()
        if row is None: break
        if row[0] == 1: # Mail
            contacts[key].AddMail(row[2])
        elif row[0] == 6: # Name
            if row[4]:
                contacts[key].SetLastname(row[4])
            if row[3]:
                contacts[key].SetFirstname(row[3])
        elif row[0] == 5: # Phone
            if row[3] == 2: # Mobile?
                pass
            elif row[3] == 1: # Home?
                pass
            contacts[key].AddPhone(row[2])

fp = codecs.open(sys.argv[2], "w", "utf-8")
fp.write(u'\ufeff')
print "Contact's Details: "
for key in contacts.keys():
    if contacts[key].GetId() != 0:
        string = ""
        last, first = contacts[key].GetName()
        if len(last) > 0 and len(first) > 0:
            string += last + " " + first
        elif len(last) > 0:
            string += last
        elif len(first) > 0:
            string += first
        phones = contacts[key].GetPhones()
        for phone in phones:
            string += phone + " "
        mails = contacts[key].GetMails()
        for mail in mails:
            string += mail + " "
        print string
        fp.write("\n".join(contacts[key].GetVCard()))
        fp.write("\n")

fp.close()
c.close()
db.close()
2015/02/20 14:09 · Andreas Böhler · 2 Comments

Extracting lecture slides from Video

Sometimes, I get lecture videos online, but no slides in PDF or whatever other format, or I could buy the slides for a few euros.

Luckily, being a computer enthusiast, I looked for a quick, easy way to extract the slides from the videos, without too much hassle. My first try was to rely on the video encoder to correctly use keyframes, but it turned out that I ended up with 1000 images for 15 slides. Dooh.

Next try: postprocessing the slides and removing duplicate ones. I came up with a very simple python script, that now runs ffmpeg to extract the keyframes and then does a simple histogram comparison of the images. Now i went down to about 30 images for 15 slides - not bad, most of the dupliate ones were recorded mouse movements or slide transitions. I can live with that.

Here is the script (the histogram part is stolen from http://stackoverflow.com/questions/1927660/compare-two-images-the-python-linux-way)

#!/usr/bin/env python2

import math, operator
from PIL import Image
import sys
import os
import glob
import subprocess
import shutil

def compare(file1, file2):
    image1 = Image.open(file1)
    image2 = Image.open(file2)
    h1 = image1.histogram()
    h2 = image2.histogram()
    rms = math.sqrt(reduce(operator.add,
                           map(lambda a,b: (a-b)**2, h1, h2))/len(h1))
    return rms

if __name__=='__main__':
    if len(sys.argv) < 3:
        sys.exit("Need video file and output dir as parameter")
    if not os.path.exists("decomp"):
        os.mkdir("decomp")
    else:
        sys.exit("decomp already exists, exit")
    if not os.path.exists(sys.argv[2]):
        os.mkdir(sys.argv[2])

    cmd = ["ffmpeg", "-i", sys.argv[1], "-vf", "select='eq(pict_type,I)'", "-vsync", "0", "-f", "image2", "decomp/%09d.png"]

    print "Running ffmpeg: " + " ".join(cmd)

    subprocess.call(cmd)

    print "Done, now eliminating duplicate images and moving unique ones to output folder..."

    filelist = glob.glob(os.path.join("decomp", '*.png'))
    filelist.sort()
    for ii in range(0, len(filelist)):
        if ii < len(filelist)-1:
            if compare(filelist[ii], filelist[ii+1]) == 0:
                print 'Found similar images: ' + filelist[ii] + " and " + filelist[ii+1]
            else:
                print 'Found unique image: ' + filelist[ii]
                head, tail = os.path.split(filelist[ii])
                shutil.copyfile(filelist[ii], sys.argv[2] + os.path.sep + tail)
        else:
            shutil.copyfile(filelist[ii], sys.argv[2] + os.path.sep + tail)
    shutil.rmtree("decomp")
2015/02/20 14:08 · Andreas Böhler
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies