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