Index: /trunk/db_postgres.go
===================================================================
--- /trunk/db_postgres.go	(revision 644)
+++ /trunk/db_postgres.go	(revision 645)
@@ -2,4 +2,5 @@
 
 import (
+	"context"
 	"database/sql"
 	"errors"
@@ -11,4 +12,6 @@
 	_ "github.com/lib/pq"
 )
+
+const postgresQueryTimeout = 5 * time.Second
 
 const postgresConfigSchema = `
@@ -146,6 +149,9 @@
 
 func (db *PostgresDB) Stats() (*DatabaseStats, error) {
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
 	var stats DatabaseStats
-	row := db.db.QueryRow(`SELECT
+	row := db.db.QueryRowContext(ctx, `SELECT
 		(SELECT COUNT(*) FROM "User") AS users,
 		(SELECT COUNT(*) FROM "Network") AS networks,
@@ -159,5 +165,9 @@
 
 func (db *PostgresDB) ListUsers() ([]User, error) {
-	rows, err := db.db.Query(`SELECT id, username, password, admin, realname FROM "User"`)
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
+	rows, err := db.db.QueryContext(ctx,
+		`SELECT id, username, password, admin, realname FROM "User"`)
 	if err != nil {
 		return nil, err
@@ -184,8 +194,11 @@
 
 func (db *PostgresDB) GetUser(username string) (*User, error) {
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
 	user := &User{Username: username}
 
 	var password, realname sql.NullString
-	row := db.db.QueryRow(
+	row := db.db.QueryRowContext(ctx,
 		`SELECT id, password, admin, realname FROM "User" WHERE username = $1`,
 		username)
@@ -199,4 +212,7 @@
 
 func (db *PostgresDB) StoreUser(user *User) error {
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
 	password := toNullString(user.Password)
 	realname := toNullString(user.Realname)
@@ -204,5 +220,5 @@
 	var err error
 	if user.ID == 0 {
-		err = db.db.QueryRow(`
+		err = db.db.QueryRowContext(ctx, `
 			INSERT INTO "User" (username, password, admin, realname)
 			VALUES ($1, $2, $3, $4)
@@ -210,5 +226,5 @@
 			user.Username, password, user.Admin, realname).Scan(&user.ID)
 	} else {
-		_, err = db.db.Exec(`
+		_, err = db.db.ExecContext(ctx, `
 			UPDATE "User"
 			SET password = $1, admin = $2, realname = $3
@@ -220,10 +236,16 @@
 
 func (db *PostgresDB) DeleteUser(id int64) error {
-	_, err := db.db.Exec(`DELETE FROM "User" WHERE id = $1`, id)
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
+	_, err := db.db.ExecContext(ctx, `DELETE FROM "User" WHERE id = $1`, id)
 	return err
 }
 
 func (db *PostgresDB) ListNetworks(userID int64) ([]Network, error) {
-	rows, err := db.db.Query(`
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
+	rows, err := db.db.QueryContext(ctx, `
 		SELECT id, name, addr, nick, username, realname, pass, connect_commands, sasl_mechanism,
 			sasl_plain_username, sasl_plain_password, sasl_external_cert, sasl_external_key, enabled
@@ -266,4 +288,7 @@
 
 func (db *PostgresDB) StoreNetwork(userID int64, network *Network) error {
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
 	netName := toNullString(network.Name)
 	netUsername := toNullString(network.Username)
@@ -290,5 +315,5 @@
 	var err error
 	if network.ID == 0 {
-		err = db.db.QueryRow(`
+		err = db.db.QueryRowContext(ctx, `
 			INSERT INTO "Network" ("user", name, addr, nick, username, realname, pass, connect_commands,
 				sasl_mechanism, sasl_plain_username, sasl_plain_password, sasl_external_cert,
@@ -300,5 +325,5 @@
 			network.SASL.External.PrivKeyBlob, network.Enabled).Scan(&network.ID)
 	} else {
-		_, err = db.db.Exec(`
+		_, err = db.db.ExecContext(ctx, `
 			UPDATE "Network"
 			SET name = $2, addr = $3, nick = $4, username = $5, realname = $6, pass = $7,
@@ -315,10 +340,16 @@
 
 func (db *PostgresDB) DeleteNetwork(id int64) error {
-	_, err := db.db.Exec(`DELETE FROM "Network" WHERE id = $1`, id)
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
+	_, err := db.db.ExecContext(ctx, `DELETE FROM "Network" WHERE id = $1`, id)
 	return err
 }
 
 func (db *PostgresDB) ListChannels(networkID int64) ([]Channel, error) {
-	rows, err := db.db.Query(`
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
+	rows, err := db.db.QueryContext(ctx, `
 		SELECT id, name, key, detached, detached_internal_msgid, relay_detached, reattach_on, detach_after,
 			detach_on
@@ -351,4 +382,7 @@
 
 func (db *PostgresDB) StoreChannel(networkID int64, ch *Channel) error {
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
 	key := toNullString(ch.Key)
 	detachAfter := int64(math.Ceil(ch.DetachAfter.Seconds()))
@@ -356,5 +390,5 @@
 	var err error
 	if ch.ID == 0 {
-		err = db.db.QueryRow(`
+		err = db.db.QueryRowContext(ctx, `
 			INSERT INTO "Channel" (network, name, key, detached, detached_internal_msgid, relay_detached, reattach_on,
 				detach_after, detach_on)
@@ -364,5 +398,5 @@
 			ch.RelayDetached, ch.ReattachOn, detachAfter, ch.DetachOn).Scan(&ch.ID)
 	} else {
-		_, err = db.db.Exec(`
+		_, err = db.db.ExecContext(ctx, `
 			UPDATE "Channel"
 			SET name = $2, key = $3, detached = $4, detached_internal_msgid = $5,
@@ -376,10 +410,16 @@
 
 func (db *PostgresDB) DeleteChannel(id int64) error {
-	_, err := db.db.Exec(`DELETE FROM "Channel" WHERE id = $1`, id)
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
+	_, err := db.db.ExecContext(ctx, `DELETE FROM "Channel" WHERE id = $1`, id)
 	return err
 }
 
 func (db *PostgresDB) ListDeliveryReceipts(networkID int64) ([]DeliveryReceipt, error) {
-	rows, err := db.db.Query(`
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
+	rows, err := db.db.QueryContext(ctx, `
 		SELECT id, target, client, internal_msgid
 		FROM "DeliveryReceipt"
@@ -406,4 +446,7 @@
 
 func (db *PostgresDB) StoreClientDeliveryReceipts(networkID int64, client string, receipts []DeliveryReceipt) error {
+	ctx, cancel := context.WithTimeout(context.TODO(), postgresQueryTimeout)
+	defer cancel()
+
 	tx, err := db.db.Begin()
 	if err != nil {
@@ -412,5 +455,6 @@
 	defer tx.Rollback()
 
-	_, err = tx.Exec(`DELETE FROM "DeliveryReceipt" WHERE network = $1 AND client = $2`,
+	_, err = tx.ExecContext(ctx,
+		`DELETE FROM "DeliveryReceipt" WHERE network = $1 AND client = $2`,
 		networkID, client)
 	if err != nil {
@@ -418,5 +462,5 @@
 	}
 
-	stmt, err := tx.Prepare(`
+	stmt, err := tx.PrepareContext(ctx, `
 		INSERT INTO "DeliveryReceipt" (network, target, client, internal_msgid)
 		VALUES ($1, $2, $3, $4)
@@ -429,5 +473,7 @@
 	for i := range receipts {
 		rcpt := &receipts[i]
-		err := stmt.QueryRow(networkID, rcpt.Target, client, rcpt.InternalMsgID).Scan(&rcpt.ID)
+		err := stmt.
+			QueryRowContext(ctx, networkID, rcpt.Target, client, rcpt.InternalMsgID).
+			Scan(&rcpt.ID)
 		if err != nil {
 			return err
Index: /trunk/db_sqlite.go
===================================================================
--- /trunk/db_sqlite.go	(revision 644)
+++ /trunk/db_sqlite.go	(revision 645)
@@ -2,4 +2,5 @@
 
 import (
+	"context"
 	"database/sql"
 	"fmt"
@@ -11,4 +12,6 @@
 	_ "github.com/mattn/go-sqlite3"
 )
+
+const sqliteQueryTimeout = 5 * time.Second
 
 const sqliteSchema = `
@@ -210,6 +213,9 @@
 	defer db.lock.RUnlock()
 
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
 	var stats DatabaseStats
-	row := db.db.QueryRow(`SELECT
+	row := db.db.QueryRowContext(ctx, `SELECT
 		(SELECT COUNT(*) FROM User) AS users,
 		(SELECT COUNT(*) FROM Network) AS networks,
@@ -233,5 +239,9 @@
 	defer db.lock.RUnlock()
 
-	rows, err := db.db.Query("SELECT id, username, password, admin, realname FROM User")
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
+	rows, err := db.db.QueryContext(ctx,
+		"SELECT id, username, password, admin, realname FROM User")
 	if err != nil {
 		return nil, err
@@ -261,8 +271,13 @@
 	defer db.lock.RUnlock()
 
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
 	user := &User{Username: username}
 
 	var password, realname sql.NullString
-	row := db.db.QueryRow("SELECT id, password, admin, realname FROM User WHERE username = ?", username)
+	row := db.db.QueryRowContext(ctx,
+		"SELECT id, password, admin, realname FROM User WHERE username = ?",
+		username)
 	if err := row.Scan(&user.ID, &password, &user.Admin, &realname); err != nil {
 		return nil, err
@@ -276,4 +291,7 @@
 	db.lock.Lock()
 	defer db.lock.Unlock()
+
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
 
 	args := []interface{}{
@@ -286,8 +304,15 @@
 	var err error
 	if user.ID != 0 {
-		_, err = db.db.Exec("UPDATE User SET password = :password, admin = :admin, realname = :realname WHERE username = :username", args...)
+		_, err = db.db.ExecContext(ctx, `
+			UPDATE User SET password = :password, admin = :admin,
+				realname = :realname WHERE username = :username`,
+			args...)
 	} else {
 		var res sql.Result
-		res, err = db.db.Exec("INSERT INTO User(username, password, admin, realname) VALUES (:username, :password, :admin, :realname)", args...)
+		res, err = db.db.ExecContext(ctx, `
+			INSERT INTO
+			User(username, password, admin, realname)
+			VALUES (:username, :password, :admin, :realname)`,
+			args...)
 		if err != nil {
 			return err
@@ -303,4 +328,7 @@
 	defer db.lock.Unlock()
 
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
 	tx, err := db.db.Begin()
 	if err != nil {
@@ -309,5 +337,5 @@
 	defer tx.Rollback()
 
-	_, err = tx.Exec(`DELETE FROM DeliveryReceipt
+	_, err = tx.ExecContext(ctx, `DELETE FROM DeliveryReceipt
 		WHERE id IN (
 			SELECT DeliveryReceipt.id
@@ -320,5 +348,5 @@
 	}
 
-	_, err = tx.Exec(`DELETE FROM Channel
+	_, err = tx.ExecContext(ctx, `DELETE FROM Channel
 		WHERE id IN (
 			SELECT Channel.id
@@ -331,10 +359,10 @@
 	}
 
-	_, err = tx.Exec("DELETE FROM Network WHERE user = ?", id)
-	if err != nil {
-		return err
-	}
-
-	_, err = tx.Exec("DELETE FROM User WHERE id = ?", id)
+	_, err = tx.ExecContext(ctx, "DELETE FROM Network WHERE user = ?", id)
+	if err != nil {
+		return err
+	}
+
+	_, err = tx.ExecContext(ctx, "DELETE FROM User WHERE id = ?", id)
 	if err != nil {
 		return err
@@ -348,5 +376,9 @@
 	defer db.lock.RUnlock()
 
-	rows, err := db.db.Query(`SELECT id, name, addr, nick, username, realname, pass,
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
+	rows, err := db.db.QueryContext(ctx, `
+		SELECT id, name, addr, nick, username, realname, pass,
 			connect_commands, sasl_mechanism, sasl_plain_username, sasl_plain_password,
 			sasl_external_cert, sasl_external_key, enabled
@@ -392,4 +424,7 @@
 	db.lock.Lock()
 	defer db.lock.Unlock()
+
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
 
 	var saslMechanism, saslPlainUsername, saslPlainPassword sql.NullString
@@ -430,5 +465,5 @@
 	var err error
 	if network.ID != 0 {
-		_, err = db.db.Exec(`
+		_, err = db.db.ExecContext(ctx, `
 			UPDATE Network
 			SET name = :name, addr = :addr, nick = :nick, username = :username,
@@ -440,5 +475,5 @@
 	} else {
 		var res sql.Result
-		res, err = db.db.Exec(`
+		res, err = db.db.ExecContext(ctx, `
 			INSERT INTO Network(user, name, addr, nick, username, realname, pass,
 				connect_commands, sasl_mechanism, sasl_plain_username,
@@ -460,4 +495,7 @@
 	defer db.lock.Unlock()
 
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
 	tx, err := db.db.Begin()
 	if err != nil {
@@ -466,15 +504,15 @@
 	defer tx.Rollback()
 
-	_, err = tx.Exec("DELETE FROM DeliveryReceipt WHERE network = ?", id)
-	if err != nil {
-		return err
-	}
-
-	_, err = tx.Exec("DELETE FROM Channel WHERE network = ?", id)
-	if err != nil {
-		return err
-	}
-
-	_, err = tx.Exec("DELETE FROM Network WHERE id = ?", id)
+	_, err = tx.ExecContext(ctx, "DELETE FROM DeliveryReceipt WHERE network = ?", id)
+	if err != nil {
+		return err
+	}
+
+	_, err = tx.ExecContext(ctx, "DELETE FROM Channel WHERE network = ?", id)
+	if err != nil {
+		return err
+	}
+
+	_, err = tx.ExecContext(ctx, "DELETE FROM Network WHERE id = ?", id)
 	if err != nil {
 		return err
@@ -488,5 +526,8 @@
 	defer db.lock.RUnlock()
 
-	rows, err := db.db.Query(`SELECT
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
+	rows, err := db.db.QueryContext(ctx, `SELECT
 			id, name, key, detached, detached_internal_msgid,
 			relay_detached, reattach_on, detach_after, detach_on
@@ -521,4 +562,7 @@
 	db.lock.Lock()
 	defer db.lock.Unlock()
+
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
 
 	args := []interface{}{
@@ -538,5 +582,5 @@
 	var err error
 	if ch.ID != 0 {
-		_, err = db.db.Exec(`UPDATE Channel
+		_, err = db.db.ExecContext(ctx, `UPDATE Channel
 			SET network = :network, name = :name, key = :key, detached = :detached,
 				detached_internal_msgid = :detached_internal_msgid, relay_detached = :relay_detached,
@@ -545,5 +589,5 @@
 	} else {
 		var res sql.Result
-		res, err = db.db.Exec(`INSERT INTO Channel(network, name, key, detached, detached_internal_msgid, relay_detached, reattach_on, detach_after, detach_on)
+		res, err = db.db.ExecContext(ctx, `INSERT INTO Channel(network, name, key, detached, detached_internal_msgid, relay_detached, reattach_on, detach_after, detach_on)
 			VALUES (:network, :name, :key, :detached, :detached_internal_msgid, :relay_detached, :reattach_on, :detach_after, :detach_on)`, args...)
 		if err != nil {
@@ -559,5 +603,8 @@
 	defer db.lock.Unlock()
 
-	_, err := db.db.Exec("DELETE FROM Channel WHERE id = ?", id)
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
+	_, err := db.db.ExecContext(ctx, "DELETE FROM Channel WHERE id = ?", id)
 	return err
 }
@@ -567,5 +614,9 @@
 	defer db.lock.RUnlock()
 
-	rows, err := db.db.Query(`SELECT id, target, client, internal_msgid
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
+	rows, err := db.db.QueryContext(ctx, `
+		SELECT id, target, client, internal_msgid
 		FROM DeliveryReceipt
 		WHERE network = ?`, networkID)
@@ -596,4 +647,7 @@
 	defer db.lock.Unlock()
 
+	ctx, cancel := context.WithTimeout(context.TODO(), sqliteQueryTimeout)
+	defer cancel()
+
 	tx, err := db.db.Begin()
 	if err != nil {
@@ -602,5 +656,5 @@
 	defer tx.Rollback()
 
-	_, err = tx.Exec("DELETE FROM DeliveryReceipt WHERE network = ? AND client IS ?",
+	_, err = tx.ExecContext(ctx, "DELETE FROM DeliveryReceipt WHERE network = ? AND client IS ?",
 		networkID, toNullString(client))
 	if err != nil {
@@ -611,5 +665,6 @@
 		rcpt := &receipts[i]
 
-		res, err := tx.Exec(`INSERT INTO DeliveryReceipt(network, target, client, internal_msgid)
+		res, err := tx.ExecContext(ctx, `
+			INSERT INTO DeliveryReceipt(network, target, client, internal_msgid)
 			VALUES (:network, :target, :client, :internal_msgid)`,
 			sql.Named("network", networkID),
