diff --git a/repl/command.go b/repl/command.go
index 206c523dfb76908fe172852dc85bbeb395fab97c..e6c448805cbe187606b2efe4a712b843a36ff329 100644
--- a/repl/command.go
+++ b/repl/command.go
@@ -1254,6 +1254,7 @@ no  default expiration date will be present.  The latter should never be
 specified for a folder or else the messages will disappear.`,
 				MinArgs: 1,
 				MaxArgs: 1,
+				Action:  ActionSetDefaultExpire,
 			},
 			"EXPIRE_LIMIT": {
 				Description: `Specifies expiration limit that  is allowed for messages. Non-privileged
@@ -1268,6 +1269,7 @@ The command SHOW FOLDER/FULL will show  the  expiration  limit,  if  one
 exists.  (NOTE: SHOW FOLDER/FULL is a privileged command.)`,
 				MinArgs: 1,
 				MaxArgs: 1,
+				Action:  ActionSetExpireLimit,
 			},
 			"FOLDER": {
 				Description: `Select a folder of messages.  Identical to the SELECT command.  See help
diff --git a/repl/repl.go b/repl/repl.go
index 6f3e2363e3670d5c5c7ea924000b303d011f84dd..f7ea79e5fd323821fe00b28b5ee28389c95b9e5f 100644
--- a/repl/repl.go
+++ b/repl/repl.go
@@ -57,6 +57,7 @@ func Loop() error {
 	// TODO: END
 
 	for {
+		this.ShowBroadcast()
 		line, err := rl.Readline()
 		if err != nil {
 			if err.Error() == "Interrupt" {
diff --git a/repl/set.go b/repl/set.go
index fc7bc80f483f1e912d8348e92057597929b85a45..ae87712fd86a922f1a036c3a758d832a0d96cdd7 100644
--- a/repl/set.go
+++ b/repl/set.go
@@ -4,6 +4,7 @@ package repl
 import (
 	"errors"
 	"fmt"
+	"strconv"
 	"strings"
 
 	"git.lyda.ie/kevin/bulletin/dclish"
@@ -67,15 +68,24 @@ func ActionSetNobrief(_ *dclish.Command) error {
 }
 
 // ActionSetDefaultExpire handles the `SET DEFAULT_EXPIRE` command.
-func ActionSetDefaultExpire(_ *dclish.Command) error {
-	fmt.Println("TODO: implement ActionSetDefaultExpire.")
-	return nil
+func ActionSetDefaultExpire(cmd *dclish.Command) error {
+	value, err := strconv.ParseInt(cmd.Args[0], 10, 64)
+	if err != nil {
+		return err
+	}
+	ctx := storage.Context()
+	return this.Q.UpdateDefaultExpire(ctx, value)
 }
 
 // ActionSetExpireLimit handles the `SET EXPIRE_LIMIT` command.
-func ActionSetExpireLimit(_ *dclish.Command) error {
+func ActionSetExpireLimit(cmd *dclish.Command) error {
 	fmt.Println("TODO: implement ActionSetExpireLimit.")
-	return nil
+	value, err := strconv.ParseInt(cmd.Args[0], 10, 64)
+	if err != nil {
+		return err
+	}
+	ctx := storage.Context()
+	return this.Q.UpdateExpireLimit(ctx, value)
 }
 
 // ActionSetFolder handles the `SET FOLDER` command.  This selects a folder.
diff --git a/storage/broadcast.sql.go b/storage/broadcast.sql.go
new file mode 100644
index 0000000000000000000000000000000000000000..550d63e3d621d72e87b1eaac3afa615b4c8b880f
--- /dev/null
+++ b/storage/broadcast.sql.go
@@ -0,0 +1,93 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.29.0
+// source: broadcast.sql
+
+package storage
+
+import (
+	"context"
+	"time"
+)
+
+const clearBroadcasts = `-- name: ClearBroadcasts :exec
+DELETE FROM broadcast
+`
+
+func (q *Queries) ClearBroadcasts(ctx context.Context) error {
+	_, err := q.db.ExecContext(ctx, clearBroadcasts)
+	return err
+}
+
+const createBroadcast = `-- name: CreateBroadcast :exec
+INSERT INTO broadcast
+    (author, bell, message)
+  VALUES
+    (?, ?, ?)
+`
+
+type CreateBroadcastParams struct {
+	Author  string
+	Bell    int64
+	Message string
+}
+
+func (q *Queries) CreateBroadcast(ctx context.Context, arg CreateBroadcastParams) error {
+	_, err := q.db.ExecContext(ctx, createBroadcast, arg.Author, arg.Bell, arg.Message)
+	return err
+}
+
+const getBroadcasts = `-- name: GetBroadcasts :many
+SELECT author, bell, message, create_at FROM broadcast WHERE create_at > ? ORDER BY create_at
+`
+
+func (q *Queries) GetBroadcasts(ctx context.Context, createAt time.Time) ([]Broadcast, error) {
+	rows, err := q.db.QueryContext(ctx, getBroadcasts, createAt)
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+	var items []Broadcast
+	for rows.Next() {
+		var i Broadcast
+		if err := rows.Scan(
+			&i.Author,
+			&i.Bell,
+			&i.Message,
+			&i.CreateAt,
+		); err != nil {
+			return nil, err
+		}
+		items = append(items, i)
+	}
+	if err := rows.Close(); err != nil {
+		return nil, err
+	}
+	if err := rows.Err(); err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+const reapBroadcasts = `-- name: ReapBroadcasts :exec
+DELETE FROM broadcast WHERE julianday(create_at) > 3
+`
+
+func (q *Queries) ReapBroadcasts(ctx context.Context) error {
+	_, err := q.db.ExecContext(ctx, reapBroadcasts)
+	return err
+}
+
+const updateLastBroadcast = `-- name: UpdateLastBroadcast :exec
+UPDATE users SET last_broadcast = ? WHERE login = ?
+`
+
+type UpdateLastBroadcastParams struct {
+	LastBroadcast time.Time
+	Login         string
+}
+
+func (q *Queries) UpdateLastBroadcast(ctx context.Context, arg UpdateLastBroadcastParams) error {
+	_, err := q.db.ExecContext(ctx, updateLastBroadcast, arg.LastBroadcast, arg.Login)
+	return err
+}
diff --git a/storage/display.go b/storage/display.go
index 05f904d86292d0fb42cb3e8c51bacafde6510413..b995426bb3c58a04078b96ca9a57dbeab80ae0b6 100644
--- a/storage/display.go
+++ b/storage/display.go
@@ -61,3 +61,16 @@ func (f Folder) String() string {
 		f.Expire,
 		f.Visibility)
 }
+
+// String displays a folder (mainly used for debugging).
+func (b Broadcast) String() string {
+	bell := ""
+	if b.Bell == 1 {
+		bell = "\a\a"
+	}
+	return fmt.Sprintf("%sFrom: %s   %s\n%s\n",
+		bell,
+		b.Author,
+		b.CreateAt.Format("06-01-02 15:04:05"),
+		b.Message)
+}
diff --git a/storage/migrations/1_create_table.up.sql b/storage/migrations/1_create_table.up.sql
index acec6f82f018420ea63ef35cbb93fce6db95f451..2f066f83b26ac6ddc2f873895a4a028304860c42 100644
--- a/storage/migrations/1_create_table.up.sql
+++ b/storage/migrations/1_create_table.up.sql
@@ -1,13 +1,14 @@
 CREATE TABLE users (
-  login       VARCHAR(12)  PRIMARY KEY NOT NULL,
-  name        VARCHAR(53)  NOT NULL,
-  admin       INT          DEFAULT 0 NOT NULL,
-  moderator   INT          DEFAULT 0 NOT NULL,
-  alert       INT          DEFAULT 0 NOT NULL,  --- 0=no, 1=brief, 2=readnew
-  disabled    INT          DEFAULT 0 NOT NULL,
-  last_login  TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
-  create_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
-  update_at   TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL
+  login          VARCHAR(12)  PRIMARY KEY NOT NULL,
+  name           VARCHAR(53)  NOT NULL,
+  admin          INT          DEFAULT 0 NOT NULL,
+  moderator      INT          DEFAULT 0 NOT NULL,
+  alert          INT          DEFAULT 0 NOT NULL,  --- 0=no, 1=brief, 2=readnew
+  disabled       INT          DEFAULT 0 NOT NULL,
+  last_broadcast TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
+  last_login     TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
+  create_at      TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL,
+  update_at      TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL
 ) WITHOUT ROWID;
 
 CREATE TRIGGER users_after_update_update_at
@@ -182,3 +183,11 @@ CREATE TABLE system (
   default_expire  INT          DEFAULT -1 NOT NULL,
   expire_limit    INT          DEFAULT -1 NOT NULL
 );
+
+--- Broadcast messages.
+CREATE TABLE broadcast (
+  author          VARCHAR(12)  PRIMARY KEY NOT NULL,
+  bell            INT          DEFAULT 0 NOT NULL,
+  message         TEXT         NOT NULL,
+  create_at       TIMESTAMP    DEFAULT CURRENT_TIMESTAMP NOT NULL
+);
diff --git a/storage/models.go b/storage/models.go
index d0089adc1fe00551e8cf670913831e6452707e33..12928857ab096356a0680802cd8e5d923c2db2bb 100644
--- a/storage/models.go
+++ b/storage/models.go
@@ -8,6 +8,13 @@ import (
 	"time"
 )
 
+type Broadcast struct {
+	Author   string
+	Bell     int64
+	Message  string
+	CreateAt time.Time
+}
+
 type Folder struct {
 	Name        string
 	Always      int64
@@ -75,13 +82,14 @@ type System struct {
 }
 
 type User struct {
-	Login     string
-	Name      string
-	Admin     int64
-	Moderator int64
-	Alert     int64
-	Disabled  int64
-	LastLogin time.Time
-	CreateAt  time.Time
-	UpdateAt  time.Time
+	Login         string
+	Name          string
+	Admin         int64
+	Moderator     int64
+	Alert         int64
+	Disabled      int64
+	LastBroadcast time.Time
+	LastLogin     time.Time
+	CreateAt      time.Time
+	UpdateAt      time.Time
 }
diff --git a/storage/queries/broadcast.sql b/storage/queries/broadcast.sql
new file mode 100644
index 0000000000000000000000000000000000000000..4b5dceb74399d223c5194cd18bbe4b0cb0c68118
--- /dev/null
+++ b/storage/queries/broadcast.sql
@@ -0,0 +1,17 @@
+-- name: CreateBroadcast :exec
+INSERT INTO broadcast
+    (author, bell, message)
+  VALUES
+    (?, ?, ?);
+
+-- name: GetBroadcasts :many
+SELECT * FROM broadcast WHERE create_at > ? ORDER BY create_at;
+
+-- name: UpdateLastBroadcast :exec
+UPDATE users SET last_broadcast = ? WHERE login = ?;
+
+-- name: ClearBroadcasts :exec
+DELETE FROM broadcast;
+
+-- name: ReapBroadcasts :exec
+DELETE FROM broadcast WHERE julianday(create_at) > 3;
diff --git a/storage/queries/system.sql b/storage/queries/system.sql
new file mode 100644
index 0000000000000000000000000000000000000000..1d901a6fa72ab63553c1de1da58b3ffcb0e3a5fb
--- /dev/null
+++ b/storage/queries/system.sql
@@ -0,0 +1,5 @@
+-- name: UpdateDefaultExpire :exec
+UPDATE system SET default_expire = ? WHERE rowid = 1;
+
+-- name: UpdateExpireLimit :exec
+UPDATE system SET expire_limit = ? WHERE rowid = 1;
diff --git a/storage/standard.sql.go b/storage/standard.sql.go
index f6c4615c285fbb883b1ae91d779314aa26cc9bb4..01d0e147ccf889ed01e7d8d8e2620132607e0beb 100644
--- a/storage/standard.sql.go
+++ b/storage/standard.sql.go
@@ -660,7 +660,7 @@ func (q *Queries) ListSeen(ctx context.Context) ([]Seen, error) {
 }
 
 const listUsers = `-- name: ListUsers :many
-SELECT login, name, admin, moderator, alert, disabled, last_login, create_at, update_at FROM users
+SELECT login, name, admin, moderator, alert, disabled, last_broadcast, last_login, create_at, update_at FROM users
 `
 
 func (q *Queries) ListUsers(ctx context.Context) ([]User, error) {
@@ -679,6 +679,7 @@ func (q *Queries) ListUsers(ctx context.Context) ([]User, error) {
 			&i.Moderator,
 			&i.Alert,
 			&i.Disabled,
+			&i.LastBroadcast,
 			&i.LastLogin,
 			&i.CreateAt,
 			&i.UpdateAt,
diff --git a/storage/system.sql.go b/storage/system.sql.go
new file mode 100644
index 0000000000000000000000000000000000000000..920642d6685d8fc631d5f32ac404d471648d1256
--- /dev/null
+++ b/storage/system.sql.go
@@ -0,0 +1,28 @@
+// Code generated by sqlc. DO NOT EDIT.
+// versions:
+//   sqlc v1.29.0
+// source: system.sql
+
+package storage
+
+import (
+	"context"
+)
+
+const updateDefaultExpire = `-- name: UpdateDefaultExpire :exec
+UPDATE system SET default_expire = ? WHERE rowid = 1
+`
+
+func (q *Queries) UpdateDefaultExpire(ctx context.Context, defaultExpire int64) error {
+	_, err := q.db.ExecContext(ctx, updateDefaultExpire, defaultExpire)
+	return err
+}
+
+const updateExpireLimit = `-- name: UpdateExpireLimit :exec
+UPDATE system SET expire_limit = ? WHERE rowid = 1
+`
+
+func (q *Queries) UpdateExpireLimit(ctx context.Context, expireLimit int64) error {
+	_, err := q.db.ExecContext(ctx, updateExpireLimit, expireLimit)
+	return err
+}
diff --git a/storage/users.sql.go b/storage/users.sql.go
index 75f923ca32b1cc8c1cb0f3cfd66a085b02eaacfd..613b4c13abc8ecd3ccfa6ad4efe0c7b1ca8a7996 100644
--- a/storage/users.sql.go
+++ b/storage/users.sql.go
@@ -12,7 +12,7 @@ import (
 
 const addUser = `-- name: AddUser :one
 INSERT INTO users (login, name, admin, disabled, last_login) VALUES (?, ?, ?, ?, ?)
-RETURNING login, name, admin, moderator, alert, disabled, last_login, create_at, update_at
+RETURNING login, name, admin, moderator, alert, disabled, last_broadcast, last_login, create_at, update_at
 `
 
 type AddUserParams struct {
@@ -39,6 +39,7 @@ func (q *Queries) AddUser(ctx context.Context, arg AddUserParams) (User, error)
 		&i.Moderator,
 		&i.Alert,
 		&i.Disabled,
+		&i.LastBroadcast,
 		&i.LastLogin,
 		&i.CreateAt,
 		&i.UpdateAt,
@@ -127,7 +128,7 @@ func (q *Queries) GetLastLoginByLogin(ctx context.Context, login string) (GetLas
 }
 
 const getUser = `-- name: GetUser :one
-SELECT login, name, admin, moderator, alert, disabled, last_login, create_at, update_at FROM users WHERE login = ?
+SELECT login, name, admin, moderator, alert, disabled, last_broadcast, last_login, create_at, update_at FROM users WHERE login = ?
 `
 
 func (q *Queries) GetUser(ctx context.Context, login string) (User, error) {
@@ -140,6 +141,7 @@ func (q *Queries) GetUser(ctx context.Context, login string) (User, error) {
 		&i.Moderator,
 		&i.Alert,
 		&i.Disabled,
+		&i.LastBroadcast,
 		&i.LastLogin,
 		&i.CreateAt,
 		&i.UpdateAt,
diff --git a/this/broadcast.go b/this/broadcast.go
new file mode 100644
index 0000000000000000000000000000000000000000..5682ab74fdcb5c373378c3181e00dcb7efc6d326
--- /dev/null
+++ b/this/broadcast.go
@@ -0,0 +1,26 @@
+package this
+
+import (
+	"fmt"
+	"time"
+
+	"git.lyda.ie/kevin/bulletin/storage"
+)
+
+// ShowBroadcast print broadcast messages.
+func ShowBroadcast() {
+	ctx := storage.Context()
+	User.LastBroadcast = time.Now()
+	msgs, _ := Q.GetBroadcasts(ctx, User.LastBroadcast)
+	if len(msgs) > 0 {
+		fmt.Println("BROADCAST MSG START")
+		for i := range msgs {
+			fmt.Printf("\n%s\n", msgs[i])
+		}
+		fmt.Println("BROADCAST MSG END")
+		Q.UpdateLastBroadcast(ctx, storage.UpdateLastBroadcastParams{
+			LastBroadcast: User.LastBroadcast,
+			Login:         User.Login,
+		})
+	}
+}
diff --git a/this/this.go b/this/this.go
index 20f44b22b58685f3a26157b2b382cc75852e83a2..7cc73fabb4cd89c503224c413cc8820e57e6b041 100644
--- a/this/this.go
+++ b/this/this.go
@@ -100,10 +100,12 @@ func StartThis(login string) error {
 	if User.Disabled == 1 {
 		return errors.New("User is disabled")
 	}
+
 	Folder, err = Q.GetFolder(ctx, "GENERAL")
 	if err != nil {
 		return err
 	}
+
 	ReadFirstCall = true
 	MsgID, err = Q.NextMsgid(ctx, storage.NextMsgidParams{
 		Folder: Folder.Name,