contacts2.db do vCard/csv – czyli co zrobić jak po androidzie został nam tylko backup, a stara dobra nokia jeszcze działa :P

ehhhh, android w opakowaniu HTC to może i ładne telefony lecz ten, kto miał kontakt z polityką traktowania klienta przez HTC, wie czego można się spodziewać :/

Tak, zostałem bez telefonu, ale z backupem. Cóż, pewnie w google znajdę kilkaset narzędzi do wyciągnięcia kontaktów z backupu zrobionego z użyciem recovery clockworkmod, ale o wiele przyjemniej jest samemu pogryźć temat :D A teraz koniec biadolenia i czas do roboty.

Po przeglądnięciu backupa wyszło na to, że kontakty są w pliku contacts2.db – szybki file i już wszystko wiadomo – baza sqlite. Ha, to pogrzebiemy. W środku trochę tabel, a ta wyglądająca najlepiej to, hm o dziwo tabela o nazwie data :D Szybka analiza i już wiadomo co i jak. Każdy wiersz zawiera jeden element kontaktu – nr, email etc. Co jest w danym wierszu można wywnioskować na podstawie zawartości pól:

  • mimetype_id – zawiera cyferkę oznaczającą rodzaj danych umieszczonych w kolumnie data1
  • raw_contact_id – jeden raw id dla jednego kontaktu
  • is_primary i is_super_primary – czyli czy dany element kontakt jest głównym czy główniejszym elementem :P
  • data1 – dane kontaktu np nr telefonu, mail itp

A wiec plan jest taki – dla poszczególnych raw_contact_id wyciągać kolejne wartosci data1 w pogrupowaniu po mimetype_id. Ahh, gdyby sqlite miał cursor-y to było by to zadanie na jeden skrypcik. Ale nie ma wiec zrobię kawałek kodu w bash-u.

W pierwszej kolejności na podstawie tabeli mimetypes ustaliłem jakie mimetype_id mnie interesują, mówiąc ludzkim głosem jakie elementy kontaktu chce wyciągnąć:

mime_name=`sqlite3 contacts2.db "select _id from mimetypes where mimetype like '%/name'"`
mime_phone=`sqlite3 contacts2.db "select _id from mimetypes where mimetype like '%/phone_v2'"`
mime_email=`sqlite3 contacts2.db "select _id from mimetypes where mimetype like '%/email_v2'"`

Jak już znamy odpowiednie mimetype_id to możemy grzebać po tabeli data. Zaczniemy od wyciągnięcia wszystkich raw_contact_id dla których istnieje wartość określająca nazwę kontaktu:

rawid=(`sqlite3 contacts2.db "select raw_contact_id from data where mimetype_id = ${mime_name} and data1 not null"`)

A teraz mała pętelka, w której będziemy wyciągać interesujące nas dane kontaktów i będziemy zapisywać je w plikach vard:

for id in ${rawid[@]}; do
    # poszczegolne dane wyciagamy
    name=`sqlite3 contacts2.db "select data1 from data where mimetype_id = ${mime_name} and raw_contact_id = ${id}"`
	phone=`sqlite3 contacts2.db "select data1 from data where mimetype_id = ${mime_phone} and raw_contact_id = ${id}"`
	email=`sqlite3 contacts2.db "select data1 from data where mimetype_id = ${mime_email} and raw_contact_id = ${id}"`
	# i do pliczkow je wrzucamy
	echo "BEGIN:VCARD\nVERSION:2.1" > ${id}.vcf
	echo "N:;${name};;;" >> ${id}.vcf
	echo "TEL;CELL:${phone}" >> ${id}.vcf
	echo "EMAIL;INTERNET;ENCODING=QUOTED-PRINTABLE:"
	echo $mail | sed 's/@/=40/g'` >> ${id}.vcf
	echo "END:VCARD" >> ${id}.vcf
done

Uzyskany format vCard działa na starej dobrej nokia np e50, e51, n95 itp :P ale wysyłanie kilkuset kontaktów na telefon w postaci vCard może być upierdliwe :/ z tego powodu dopisałem kawałek kodu eksportujący kontakty do csv:

Poniżej cały skrypt, w którym dołożyłem obsługę kilku tych samych mimetype_id dla jednego kontaktu (np dwa nr telefonu itp).

#!/bin/bash
# contact@staryadmin.pl
# GNU/GPL
#

# usage
# skrypt.sh db type
# db - contacts db file eg contacts2.db
# type - csv or vcard

# config
sqle="sqlite3 $1 "

# get mimetype for name, phone, email
mime_name=`${sqle} "select _id from mimetypes where mimetype like '%/name'"`
mime_phone=`${sqle} "select _id from mimetypes where mimetype like '%/phone_v2'"`
mime_email=`${sqle} "select _id from mimetypes where mimetype like '%/email_v2'"`

# get raw_contakt_id for contacts with the name
rawid=(`${sqle} "select raw_contact_id from data where mimetype_id = ${mime_name} and data1 not null"`)

# functions
function vcard {
	# go to work ;)
	for id in ${rawid[@]}; do
	# get contact name
	name=`${sqle} "select data1 from data where mimetype_id = ${mime_name} and raw_contact_id = ${id}"`
	# get phone number - primary number
	phonep1=`${sqle} "select data1 from data where mimetype_id = ${mime_phone} and raw_contact_id = ${id} and is_primary = 1 and is_super_primary = 1"`
	# get phone numbre - next primary number :P
	phonep2=`${sqle} "select data1 from data where mimetype_id = ${mime_phone} and raw_contact_id = ${id} and is_primary = 1 and is_super_primary = 0"`
	# get phone number - rest numbers
	phone=(`${sqle} "select data1 from data where mimetype_id = ${mime_phone} and raw_contact_id = ${id} and is_primary = 0"`)
	email=(`${sqle} "select data1 from data where mimetype_id = ${mime_email} and raw_contact_id = ${id}"`)

	# and writ to vCard file
	echo "BEGIN:VCARD" > ${id}.vcf
	echo "VERSION:2.1" >> ${id}.vcf
	echo "N:;${name};;;" >> ${id}.vcf
	if [[ $phonep1 ]]; then echo "TEL;CELL:${phonep1}" >> ${id}.vcf; fi
	if [[ $phonep2 ]]; then echo "TEL;CELL:${phonep2}" >> ${id}.vcf; fi
	for ph in ${phone[@]}; do echo "TEL;CELL:${ph}" >> ${id}.vcf; done
	for em in ${email[@]}; do echo "EMAIL;INTERNET;ENCODING=QUOTED-PRINTABLE:"`echo $em | sed 's/@/=40/g'` >> ${id}.vcf; done
	echo "END:VCARD" >> ${id}.vcf
	done
}

function csv {
	# go to work ;)
	# put cvs header
	echo '"Title";"First name";"General mobile";"General phone";"Home mobile";"Home phone";"Business mobile";"Business phone";"General email";"Home email";"Business email";' > contacts.csv
	for id in ${rawid[@]}; do
		# get contact name
		name=`${sqle} "select data1 from data where mimetype_id = ${mime_name} and raw_contact_id = ${id}"`
		# get phone number - primary number
		phonep1=`${sqle} "select data1 from data where mimetype_id = ${mime_phone} and raw_contact_id = ${id} and is_primary = 1 and is_super_primary = 1"`
		# get phone numbre - next primary number :P
		phonep2=`${sqle} "select data1 from data where mimetype_id = ${mime_phone} and raw_contact_id = ${id} and is_primary = 1 and is_super_primary = 0"`
		# get phone number - rest numbers
		phone=(`${sqle} "select data1 from data where mimetype_id = ${mime_phone} and raw_contact_id = ${id} and is_primary = 0"`)
		email=(`${sqle} "select data1 from data where mimetype_id = ${mime_email} and raw_contact_id = ${id}"`)

		# and writ to csv file
		# prepare phone/mail
		i=0
		if [[ ${phonep1} ]]; then phons='"'${phonep1}'";'; i=$((${i}+1)); fi
		echo ${phonep1}", "${i} >> contacts.csv
		if [[ ${phonep2} ]]; then phons='"'${phonep2}'";'; i=$((${i}+1)); fi
		echo ${phonep2}", "${i} >> contacts.csv
		for ph in ${phone[@]}; do phons='"'${ph}'";'; i=$((${i}+1)); echo ${ph}", "${i} >> contacts.csv; if [[ ${i} -eq 6 ]]; then break; fi; done
		if [[ ${i} -lt 6 ]]; then for n in $(seq ${i} 5); do phons=${phons}'"";'; done; fi
		i=0
		for em in ${email[@]}; do emails='"a'${em}'";'; i=$((${i}+1)); if [[ ${i} -eq 6 ]]; then break; fi; done
		echo '"";"'${name}'";'${phons}${emails} >> contacts.csv
	done
}

# run convert
$2

a w dalszych planach mam zamiar przepisać to na binarny kod backupów symbianowych.